less beta release (part 5 of 5)

Mark Nudelman mark at unix386.Convergent.COM
Fri Sep 15 08:25:28 AEST 1989


#! /bin/sh
# This is a shell archive.
# Remove anything before this line, then unpack it
# by saving it into a file and typing "sh file".

echo shar: Extracting \"prim1.c\"
sed "s/^X//" >'prim1.c' <<'END_OF_FILE'
X/*
X * Primitives for displaying the file on the screen.
X */
X
X#include "less.h"
X#include "position.h"
X
Xpublic int hit_eof;	/* Keeps track of how many times we hit end of file */
Xpublic int screen_trashed;
X
Xstatic int squished;
X
Xextern int sigs;
Xextern int top_scroll;
Xextern int quiet;
Xextern int sc_width, sc_height;
Xextern int quit_at_eof;
Xextern int plusoption;
Xextern char *first_cmd;
X#if TAGS
Xextern int tagoption;
X#endif
X
X/*
X * Sound the bell to indicate user is trying to move past end of file.
X */
X	static void
Xeof_bell()
X{
X	if (quiet == NOT_QUIET)
X		bell();
X	else
X		vbell();
X}
X
X/*
X * Check to see if the end of file is currently "displayed".
X */
X	static void
Xeof_check()
X{
X	POSITION pos;
X
X	if (sigs)
X		return;
X	/*
X	 * If the bottom line is empty, we are at EOF.
X	 * If the bottom line ends at the file length,
X	 * we must be just at EOF.
X	 */
X	pos = position(BOTTOM_PLUS_ONE);
X	if (pos == NULL_POSITION || pos == ch_length())
X		hit_eof++;
X}
X
X/*
X * If the screen is "squished", repaint it.
X * "Squished" means the first displayed line is not at the top
X * of the screen; this can happen when we display a short file
X * for the first time.
X */
X	static void
Xsquish_check()
X{
X	if (!squished)
X		return;
X	squished = 0;
X	repaint();
X}
X
X/*
X * Display n lines, scrolling forward, 
X * starting at position pos in the input file.
X * "force" means display the n lines even if we hit end of file.
X * "only_last" means display only the last screenful if n > screen size.
X */
X	static void
Xforw(n, pos, force, only_last)
X	register int n;
X	POSITION pos;
X	int force;
X	int only_last;
X{
X	int eof = 0;
X	int nlines = 0;
X	int do_repaint;
X	static int first_time = 1;
X
X	squish_check();
X
X	/*
X	 * do_repaint tells us not to display anything till the end, 
X	 * then just repaint the entire screen.
X	 */
X	do_repaint = (only_last && n > sc_height-1);
X
X	if (!do_repaint)
X	{
X		if (top_scroll && n >= sc_height - 1)
X		{
X			/*
X			 * Start a new screen.
X			 * {{ This is not really desirable if we happen
X			 *    to hit eof in the middle of this screen,
X			 *    but we don't yet know if that will happen. }}
X			 */
X			if (top_scroll == 2)
X				clear();
X			home();
X			force = 1;
X		} else
X		{
X			lower_left();
X			clear_eol();
X		}
X
X		if (pos != position(BOTTOM_PLUS_ONE))
X		{
X			/*
X			 * This is not contiguous with what is
X			 * currently displayed.  Clear the screen image 
X			 * (position table) and start a new screen.
X			 */
X			pos_clear();
X			add_forw_pos(pos);
X			force = 1;
X			if (top_scroll)
X			{
X				if (top_scroll == 2)
X					clear();
X				home();
X			} else if (!first_time)
X			{
X				putstr("...skipping...\n");
X			}
X		}
X	}
X
X	while (--n >= 0)
X	{
X		/*
X		 * Read the next line of input.
X		 */
X		pos = forw_line(pos);
X		if (pos == NULL_POSITION)
X		{
X			/*
X			 * End of file: stop here unless the top line 
X			 * is still empty, or "force" is true.
X			 */
X			eof = 1;
X			if (!force && position(TOP) != NULL_POSITION)
X				break;
X		}
X		/*
X		 * Add the position of the next line to the position table.
X		 * Display the current line on the screen.
X		 */
X		add_forw_pos(pos);
X		nlines++;
X		if (do_repaint)
X			continue;
X		/*
X		 * If this is the first screen displayed and
X		 * we hit an early EOF (i.e. before the requested
X		 * number of lines), we "squish" the display down
X		 * at the bottom of the screen.
X		 * But don't do this if a + option or a -t option
X		 * was given.  These options can cause us to
X		 * start the display after the beginning of the file,
X		 * and it is not appropriate to squish in that case.
X		 */
X		if (first_time && pos == NULL_POSITION && !top_scroll && 
X#if TAGS
X		    !tagoption &&
X#endif
X		    !plusoption)
X		{
X			squished = 1;
X			continue;
X		}
X		if (top_scroll == 1)
X			clear_eol();
X		put_line();
X	}
X
X	if (eof && !sigs)
X		hit_eof++;
X	else
X		eof_check();
X	if (nlines == 0)
X		eof_bell();
X	else if (do_repaint)
X		repaint();
X	first_time = 0;
X	(void) currline(BOTTOM);
X}
X
X/*
X * Display n lines, scrolling backward.
X */
X	static void
Xback(n, pos, force, only_last)
X	register int n;
X	POSITION pos;
X	int force;
X	int only_last;
X{
X	int nlines = 0;
X	int do_repaint;
X
X	squish_check();
X	do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
X	hit_eof = 0;
X	while (--n >= 0)
X	{
X		/*
X		 * Get the previous line of input.
X		 */
X		pos = back_line(pos);
X		if (pos == NULL_POSITION)
X		{
X			/*
X			 * Beginning of file: stop here unless "force" is true.
X			 */
X			if (!force)
X				break;
X		}
X		/*
X		 * Add the position of the previous line to the position table.
X		 * Display the line on the screen.
X		 */
X		add_back_pos(pos);
X		nlines++;
X		if (!do_repaint)
X		{
X			home();
X			add_line();
X			put_line();
X		}
X	}
X
X	eof_check();
X	if (nlines == 0)
X		eof_bell();
X	else if (do_repaint)
X		repaint();
X	(void) currline(BOTTOM);
X}
X
X/*
X * Display n more lines, forward.
X * Start just after the line currently displayed at the bottom of the screen.
X */
X	public void
Xforward(n, only_last)
X	int n;
X	int only_last;
X{
X	POSITION pos;
X
X	if (quit_at_eof && hit_eof)
X	{
X		/*
X		 * If the -e flag is set and we're trying to go
X		 * forward from end-of-file, go on to the next file.
X		 */
X		next_file(1);
X		return;
X	}
X
X	pos = position(BOTTOM_PLUS_ONE);
X	if (pos == NULL_POSITION)
X	{
X		eof_bell();
X		hit_eof++;
X		return;
X	}
X	forw(n, pos, 0, only_last);
X}
X
X/*
X * Display n more lines, backward.
X * Start just before the line currently displayed at the top of the screen.
X */
X	public void
Xbackward(n, only_last)
X	int n;
X	int only_last;
X{
X	POSITION pos;
X
X	pos = position(TOP);
X	if (pos == NULL_POSITION)
X	{
X		/* 
X		 * This will almost never happen,
X		 * because the top line is almost never empty. 
X		 */
X		eof_bell();
X		return;   
X	}
X	back(n, pos, 0, only_last);
X}
X
X/*
X * Repaint the screen, starting from a specified position.
X */
X	static void
Xprepaint(pos)	
X	POSITION pos;
X{
X	hit_eof = 0;
X	squished = 0;
X	screen_trashed = 0;
X	forw(sc_height-1, pos, 1, 0);
X}
X
X/*
X * Repaint the screen.
X */
X	public void
Xrepaint()
X{
X	/*
X	 * Start at the line currently at the top of the screen
X	 * and redisplay the screen.
X	 */
X	prepaint(position(TOP));
X}
X
X/*
X * Jump to the end of the file.
X * It is more convenient to paint the screen backward,
X * from the end of the file toward the beginning.
X */
X	public void
Xjump_forw()
X{
X	POSITION pos;
X
X	if (ch_end_seek())
X	{
X		error("Cannot seek to end of file");
X		return;
X	}
X	lastmark();
X	pos = ch_tell();
X	clear();
X	pos_clear();
X	add_back_pos(pos);
X	screen_trashed = 0;
X	back(sc_height - 1, pos, 0, 0);
X}
X
X/*
X * Jump to line n in the file.
X */
X	public void
Xjump_back(n)
X	int n;
X{
X	POSITION pos;
X	char m[50];
X
X	pos = find_pos(n);
X	if (pos != NULL_POSITION && ch_seek(pos) == 0)
X	{
X		jump_loc(pos);
X	} else if (n <= 1 && ch_beg_seek() == 0)
X	{
X		jump_loc(ch_tell());
X		error("Cannot seek to beginning of file");
X	} else
X	{
X		sprintf(m, "Cannot seek to line number %d", n);
X		error(m);
X	}
X}
X
X/*
X * Jump to a specified position in the file.
X * The position must be the first character in a line.
X */
X	public void
Xjump_loc(pos)
X	POSITION pos;
X{
X	register int nline;
X	POSITION tpos;
X
X	if ((nline = onscreen(pos)) >= 0)
X	{
X		/*
X		 * The line is currently displayed.  
X		 * Just scroll there.
X		 */
X		forw(nline, position(BOTTOM_PLUS_ONE), 1, 0);
X		return;
X	}
X
X	/*
X	 * Line is not on screen.
X	 * Seek to the desired location.
X	 */
X	if (ch_seek(pos))
X	{
X		error("Cannot seek to that file position");
X		return;
X	}
X
X	/*
X	 * See if the desired line is BEFORE the currently
X	 * displayed screen.  If so, then move forward far
X	 * enough so the line we're on will be at the bottom
X	 * of the screen, in order to be able to call back()
X	 * to make the screen scroll backwards & put the line
X	 * at the top of the screen.
X	 * {{ This seems inefficient, but it's not so bad,
X	 *    since we can never move forward more than a
X	 *    screenful before we stop to redraw the screen. }}
X	 */
X	tpos = position(TOP);
X	if (tpos != NULL_POSITION && pos < tpos)
X	{
X		POSITION npos = pos;
X		/*
X		 * Note that we can't forw_line() past tpos here,
X		 * so there should be no EOI at this stage.
X		 */
X		for (nline = 0;  npos < tpos && nline < sc_height - 1;  nline++)
X			npos = forw_line(npos);
X
X		if (npos < tpos)
X		{
X			/*
X			 * More than a screenful back.
X			 */
X			lastmark();
X			clear();
X			pos_clear();
X			add_back_pos(npos);
X		}
X
X		/*
X		 * Note that back() will repaint() if nline > back_scroll.
X		 */
X		back(nline, npos, 1, 0);
X		return;
X	}
X	/*
X	 * Remember where we were; clear and paint the screen.
X	 */
X  	lastmark();
X  	prepaint(pos);
X}
END_OF_FILE
echo shar: Extracting \"prim2.c\"
sed "s/^X//" >'prim2.c' <<'END_OF_FILE'
X/*
X * More primitives for displaying the file on the screen.
X */
X
X#include "less.h"
X#include "position.h"
X
Xextern int sigs;
Xextern int how_search;
Xextern int top_scroll;
Xextern int back_scroll;
Xextern int caseless;
Xextern int linenums;
Xextern int sc_height;
Xextern HANDLE curr_handle;
X
X/*
X * Jump to a specified position in the file.
X * The position need not be the first character in a line.
X */
X	static void
Xjump_line_loc(pos)
X	POSITION pos;
X{
X	int c;
X
X	if (ch_seek(pos) == 0)
X	{
X		/*
X		 * Back up to the beginning of the line.
X		 */
X		while ((c = ch_back_get()) != '\n' && c != EOI)
X			;
X		if (c == '\n')
X			(void) ch_forw_get();
X		pos = ch_tell();
X	}
X	jump_loc(pos);
X}
X
X/*
X * Jump to a specified percentage into the file.
X * This is a poor compensation for not being able to
X * quickly jump to a specific line number.
X */
X	public void
Xjump_percent(percent)
X	int percent;
X{
X	POSITION pos, len;
X
X	/*
X	 * Determine the position in the file
X	 * (the specified percentage of the file's length).
X	 */
X	if ((len = ch_length()) == NULL_POSITION)
X	{
X		error("Don't know length of file");
X		return;
X	}
X	pos = (percent * len) / 100;
X
X	jump_line_loc(pos);
X}
X
X/*
X * The table of marks.
X * A mark is simply a position in a file and the handle of the file.
X */
X#define	NMARKS		(27)		/* 26 for a-z plus one for quote */
X#define	LASTMARK	(NMARKS-1)	/* For quote */
X
Xstatic struct mark {
X	HANDLE m_handle;
X	POSITION m_pos;
X} marks[NMARKS];
X
X/*
X * Initialize the mark table to show no marks are set.
X */
X	public void
Xinit_mark()
X{
X	int i;
X
X	for (i = 0;  i < NMARKS;  i++)
X		marks[i].m_pos = NULL_POSITION;
X}
X
X/*
X * See if a mark letter is valid (between a and z).
X */
X	static int
Xbadmark(c)
X	int c;
X{
X	if (c < 'a' || c > 'z')
X	{
X		error("Choose a letter between 'a' and 'z'");
X		return (1);
X	}
X	return (0);
X}
X
X/*
X * Set a mark.
X */
X	public void
Xsetmark(c)
X	int c;
X{
X	if (badmark(c))
X		return;
X	c -= 'a';
X	marks[c].m_pos = position(TOP);
X	marks[c].m_handle = curr_handle;
X}
X
X/*
X * Set the LASTMARK (the mark named by the apostrophe).
X */
X	public void
Xlastmark()
X{
X	POSITION pos;
X
X	pos = position(TOP);
X	if (pos == NULL_POSITION)
X		return;
X	marks[LASTMARK].m_pos = pos;
X	marks[LASTMARK].m_handle = curr_handle;
X}
X
X/*
X * Go to a previously set mark.
X */
X	public void
Xgomark(c)
X	int c;
X{
X	POSITION pos;
X	HANDLE handle;
X
X	if (c == '\'')
X		c = LASTMARK;
X	else if (badmark(c))
X		return;
X	else 
X		c -= 'a';
X
X	pos = marks[c].m_pos;
X	handle = marks[c].m_handle;
X	if (pos == NULL_POSITION)
X	{
X		error("Mark not set");
X		return;
X	}
X
X	if (handle != curr_handle)
X		/*
X		 * Not in the current file; edit the correct file.
X		 */
X		edit(get_filename(handle));
X
X	jump_loc(pos);
X}
X
X/*
X * Get the backwards scroll limit.
X * Must call this function instead of just using the value of
X * back_scroll, because the default case depends on sc_height and
X * top_scroll, as well as back_scroll.
X */
X	public int
Xget_back_scroll()
X{
X	if (back_scroll >= 0)
X		return (back_scroll);
X	if (top_scroll)
X		return (sc_height - 2);
X	return (10000); /* infinity */
X}
X
X/*
X * Try to match the n-th bracket of the specified type 
X * which appears in the top displayed line.
X * brac may be '\0' to mean look for any bracket.
X * "Bracket" refers to any of the pairs: { }, [ ], or ( ).
X */
X	public void
Xmatch_brac(brac, n)
X	register int brac;
X	int n;
X{
X	register int c;
X	register int nest;
X	int obrac, cbrac;
X	int forwdir;
X	POSITION pos;
X	int (*chget)();
X
X	extern int ch_forw_get(), ch_back_get();
X
X	pos = position(TOP);
X	if (pos == NULL_POSITION || ch_seek(pos))
X	{
X		error("Nothing in top line");
X		return;
X	}
X
X	/*
X	 * Look thru the first line to find the type of bracket to match.
X	 */
X	for (;;)
X	{
X		if ((c = ch_forw_get()) == '\n' || c == EOI)
X		{
X			error("No bracket in top line");
X			return;
X		}
X		if (brac != '\0' && brac != c)
X			/*
X			 * This is not the specified bracket character.
X			 */
X			continue;
X
X		switch (c)
X		{
X		default:  continue;
X		case '{':   obrac = '{';  cbrac = '}';  forwdir = 1;  break;
X		case '}':   obrac = '}';  cbrac = '{';  forwdir = 0;  break;
X		case '[':   obrac = '[';  cbrac = ']';  forwdir = 1;  break;
X		case ']':   obrac = ']';  cbrac = '[';  forwdir = 0;  break;
X		case '(':   obrac = '(';  cbrac = ')';  forwdir = 1;  break;
X		case ')':   obrac = ')';  cbrac = '(';  forwdir = 0;  break;
X		}
X		/*
X		 * See if we have the n-th bracket in the line.
X		 */
X		if (--n <= 0)
X			break;
X	}
X
X	if (!forwdir)
X	{
X		/*
X		 * Position the file just "after" the open bracket.
X		 * That is, if searching backwards, skip back over 
X		 * the open bracket now.
X		 */
X		(void) ch_back_get();
X	}
X
X	/*
X	 * Search the file for the matching bracket.
X	 */
X	chget = (forwdir) ? ch_forw_get : ch_back_get;
X	nest = 0;
X	while ((c = (*chget)()) != EOI)
X	{
X		if (c == obrac)
X			nest++;
X		else if (c == cbrac && --nest < 0)
X		{
X			jump_line_loc(ch_tell());
X			return;
X		}
X	}
X	error("No matching bracket");
X}
X
X/*
X * Search for the n-th occurrence of a specified pattern, 
X * either forward or backward.
X */
X	public void
Xsearch(search_type, pattern, n)
X	int search_type;
X	char *pattern;
X	register int n;
X{
X	POSITION pos, linepos;
X	register char *p;
X	register char *q;
X	register int goforw;
X	register int wantmatch;
X	char *line;
X	int linenum;
X	int linematch;
X#if RECOMP
X	char *re_comp();
X	char *errmsg;
X#else
X#if REGCMP
X	char *regcmp();
X	static char *cpattern = NULL;
X#else
X	static char lpbuf[100];
X	static char *last_pattern = NULL;
X#endif
X#endif
X
X	/*
X	 * Extract flags and type of search.
X	 */
X	wantmatch = !(search_type & SRCH_NOMATCH);
X	search_type = SRCH_TYPE(search_type);
X
X	if (caseless && pattern != NULL)
X	{
X		/*
X		 * For a caseless search, convert any uppercase
X		 * in the pattern to lowercase.
X		 */
X		for (p = pattern;  *p != '\0';  p++)
X			if (*p >= 'A' && *p <= 'Z')
X				*p += 'a' - 'A';
X	}
X#if RECOMP
X
X	/*
X	 * (re_comp handles a null pattern internally, 
X	 *  so there is no need to check for a null pattern here.)
X	 */
X	if ((errmsg = re_comp(pattern)) != NULL)
X	{
X		error(errmsg);
X		return;
X	}
X#else
X#if REGCMP
X	if (pattern == NULL || *pattern == '\0')
X	{
X		/*
X		 * A null pattern means use the previous pattern.
X		 * The compiled previous pattern is in cpattern, so just use it.
X		 */
X		if (cpattern == NULL)
X		{
X			error("No previous regular expression");
X			return;
X		}
X	} else
X	{
X		/*
X		 * Otherwise compile the given pattern.
X		 */
X		char *s;
X		if ((s = regcmp(pattern, 0)) == NULL)
X		{
X			error("Invalid pattern");
X			return;
X		}
X		if (cpattern != NULL)
X			free(cpattern);
X		cpattern = s;
X	}
X#else
X	if (pattern == NULL || *pattern == '\0')
X	{
X		/*
X		 * Null pattern means use the previous pattern.
X		 */
X		if (last_pattern == NULL)
X		{
X			error("No previous regular expression");
X			return;
X		}
X		pattern = last_pattern;
X	} else
X	{
X		strcpy(lpbuf, pattern);
X		last_pattern = lpbuf;
X	}
X#endif
X#endif
X
X	/*
X	 * Figure out where to start the search.
X	 */
X
X	if (search_type == SRCH_FILE)
X	{
X		/*
X		 * User wants to start searching at beginning of file.
X		 * {{ Use ch_beg_seek() in case we can't seek to 0? }}
X		 */
X		pos = (POSITION)0;
X		goforw = 1;
X	} else if (position(TOP) == NULL_POSITION)
X	{
X		/*
X		 * Nothing is currently displayed.
X		 * Start at the beginning of the file.
X		 * (This case is mainly for first_cmd searches,
X		 * for example, "+/xyz" on the command line.)
X		 */
X		pos = (POSITION)0;
X		goforw = 1;
X	} else if (search_type == SRCH_BACK)
X	{
X		/*
X		 * Backward search: start just before the top line
X		 * displayed on the screen.
X		 */
X		pos = position(TOP);
X		goforw = 0;
X	} else if (how_search == 0)
X	{
X		/*
X		 * Start at the second real line displayed on the screen.
X		 */
X		pos = position(TOP);
X		do
X			pos = forw_raw_line(pos, (char **)NULL);
X		while (pos < position(TOP_PLUS_ONE));
X		goforw = 1;
X	} else if (how_search == 1)
X	{
X		/*
X		 * Start just after the bottom line displayed on the screen.
X		 */
X		pos = position(BOTTOM_PLUS_ONE);
X		goforw = 1;
X	} else
X	{
X		/*
X		 * Start at the second screen line displayed on the screen.
X		 */
X		pos = position(TOP_PLUS_ONE);
X		goforw = 1;
X	}
X
X	if (pos == NULL_POSITION)
X	{
X		/*
X		 * Can't find anyplace to start searching from.
X		 */
X		error("Nothing to search");
X		return;
X	}
X
X	linenum = find_linenum(pos);
X	for (;;)
X	{
X		/*
X		 * Get lines until we find a matching one or 
X		 * until we hit end-of-file (or beginning-of-file 
X		 * if we're going backwards).
X		 */
X		if (sigs)
X			/*
X			 * A signal aborts the search.
X			 */
X			return;
X
X		if (goforw)
X		{
X			/*
X			 * Read the next line, and save the 
X			 * starting position of that line in linepos.
X			 */
X			linepos = pos;
X			pos = forw_raw_line(pos, &line);
X			if (linenum != 0)
X				linenum++;
X		} else
X		{
X			/*
X			 * Read the previous line and save the
X			 * starting position of that line in linepos.
X			 */
X			pos = back_raw_line(pos, &line);
X			linepos = pos;
X			if (linenum != 0)
X				linenum--;
X		}
X
X		if (pos == NULL_POSITION)
X		{
X			/*
X			 * We hit EOF/BOF without a match.
X			 */
X			error("Pattern not found");
X			return;
X		}
X
X		/*
X		 * If we're using line numbers, we might as well
X		 * remember the information we have now (the position
X		 * and line number of the current line).
X		 */
X		if (linenums)
X			add_lnum(linenum, pos);
X
X		if (caseless)
X		{
X			/*
X			 * If this is a caseless search, convert 
X			 * uppercase in the input line to lowercase.
X			 * While we're at it, remove any backspaces
X			 * along with the preceding char.
X			 * This allows us to match text which is 
X			 * underlined or overstruck.
X			 */
X			for (p = q = line;  *p != '\0';  p++, q++)
X			{
X				if (*p >= 'A' && *p <= 'Z')
X					/* Convert uppercase to lowercase. */
X					*q = *p + 'a' - 'A';
X				else if (q > line && *p == '\b')
X					/* Delete BS and preceding char. */
X					q -= 2;
X				else
X					/* Otherwise, just copy. */
X					*q = *p;
X			}
X		}
X
X		/*
X		 * Test the next line to see if we have a match.
X		 * This is done in a variety of ways, depending
X		 * on what pattern matching functions are available.
X		 */
X#if REGCMP
X		linematch = (regex(cpattern, line) != NULL);
X#else
X#if RECOMP
X		linematch = (re_exec(line) == 1);
X#else
X		linematch = match(pattern, line);
X#endif
X#endif
X		/*
X		 * We are successful if wantmatch and linematch are
X		 * both true (want a match and got it),
X		 * or both false (want a non-match and got it).
X		 */
X		if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
X		      --n <= 0)
X			/*
X			 * Found the line.
X			 */
X			break;
X	}
X
X	jump_loc(linepos);
X}
X
X#if (!REGCMP) && (!RECOMP)
X/*
X * We have neither regcmp() nor re_comp().
X * We use this function to do simple pattern matching.
X * It supports no metacharacters like *, etc.
X */
X	static int
Xmatch(pattern, buf)
X	char *pattern, *buf;
X{
X	register char *pp, *lp;
X
X	for ( ;  *buf != '\0';  buf++)
X	{
X		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
X			if (*pp == '\0' || *lp == '\0')
X				break;
X		if (*pp == '\0')
X			return (1);
X	}
X	return (0);
X}
X#endif
END_OF_FILE
echo shar: Extracting \"prompt.c\"
sed "s/^X//" >'prompt.c' <<'END_OF_FILE'
X/*
X * Prompting and other messages.
X * There are three flavors of prompts, SHORT, MEDIUM and LONG,
X * selected by the -m/-M options.
X * There is also the "equals message", printed by the = command.
X * A prompt is a message composed of various pieces, such as the 
X * name of the file being viewed, the percentage into the file, etc.
X */
X
X#include "less.h"
X#include "position.h"
X
Xextern int pr_type;
Xextern int ispipe;
Xextern int hit_eof;
Xextern int new_file;
Xextern int sc_width;
Xextern int so_width, se_width;
Xextern char *current_file;
Xextern int ac;
Xextern char **av;
Xextern int curr_ac;
Xextern int linenums;
X#if EDITOR
Xextern char *editor;
X#endif
X
X/*
X * Prototypes for the three flavors of prompts.
X * These strings are expanded by pr_expand().
X */
Xstatic char s_proto[] =
X  "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x..%t";
Xstatic char m_proto[] =
X  "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t";
Xstatic char M_proto[] =
X  "?f%f .?n?m(file %i of %m) ..?ltline %lt?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t";
Xstatic char e_proto[] =
X  "?f%f .?m(file %i of %m) .?ltline %lt?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t";
X
Xpublic char *prproto[3];
Xpublic char *eqproto = e_proto;
X
Xstatic char message[250];
Xstatic char *mp;
X
X/*
X * Initialize the prompt prototype strings.
X */
X	public void
Xinit_prompt()
X{
X	prproto[0] = save(s_proto);
X	prproto[1] = save(m_proto);
X	prproto[2] = save(M_proto);
X	eqproto = save(e_proto);
X}
X
X/*
X * Set the message pointer to the end of the message string.
X */
X	static void
Xsetmp()
X{
X	while (*mp != '\0')
X		mp++;
X}
X
X/*
X * Append a POSITION (as a decimal integer) to the end of the message.
X */
X	static void
Xap_pos(pos)
X	POSITION pos;
X{
X	sprintf(mp, "%ld", (long)pos);
X	setmp();
X}
X
X/*
X * Append an integer to the end of the message.
X */
X	static void
Xap_int(n)
X	int n;
X{
X	sprintf(mp, "%d", n);
X	setmp();
X}
X
X/*
X * Append a string to the end of the message.
X */
X	static void
Xap_str(s)
X	char *s;
X{
X	strtcpy(mp, s, (unsigned int)(&message[sizeof(message)] - mp));
X	setmp();
X}
X
X/*
X * Append a question mark to the end of the message.
X */
X	static void
Xap_quest()
X{
X	*mp++ = '?';
X}
X
X/*
X * Return the "current" byte offset in the file.
X */
X	static POSITION
Xcurr_byte(where)
X	int where;
X{
X	POSITION pos;
X
X	pos = position(where);
X	if (pos == NULL_POSITION)
X		pos = ch_length();
X	return (pos);
X}
X
X/*
X * Return the value of a prototype conditional.
X * A prototype string may include conditionals which consist of a 
X * question mark followed by a single letter.
X * Here we decode that letter and return the appropriate boolean value.
X */
X	static int
Xcond(c, where)
X	char c;
X	int where;
X{
X	switch (c)
X	{
X	case 'a':	/* Anything in the message yet? */
X		return (mp > message);
X	case 'b':	/* Current byte offset known? */
X		return (curr_byte(where) != NULL_POSITION);
X	case 'e':	/* At end of file? */
X		return (hit_eof);
X	case 'f':	/* Filename known? */
X		return (!ispipe);
X	case 'l':	/* Line number known? */
X		return (linenums);
X	case 'L':	/* Final line number known? */
X		return (linenums && ch_length() != NULL_POSITION);
X	case 'm':	/* More than one file? */
X		return (ac > 1);
X	case 'n':	/* First prompt in a new file? */
X		return (new_file);
X	case 'p':	/* Percent into file known? */
X		return (curr_byte(where) != NULL_POSITION && 
X				ch_length() > 0);
X	case 's':	/* Size of file known? */
X		return (ch_length() != NULL_POSITION);
X	case 'x':	/* Is there a "next" file? */
X		return (curr_ac + 1 < ac);
X	}
X	return (0);
X}
X
X/*
X * Decode a "percent" prototype character.
X * A prototype string may include various "percent" escapes;
X * that is, a percent sign followed by a single letter.
X * Here we decode that letter and take the appropriate action,
X * usually by appending something to the message being built.
X */
X	static void
Xprotochar(c, where)
X	int c;
X	int where;
X{
X	POSITION pos;
X	POSITION len;
X	int n;
X
X	switch (c)
X	{
X	case 'b':	/* Current byte offset */
X		pos = curr_byte(where);
X		if (pos != NULL_POSITION)
X			ap_pos(pos);
X		else
X			ap_quest();
X		break;
X#if EDITOR
X	case 'E':	/* Editor name */
X		ap_str(editor);
X		break;
X#endif
X	case 'f':	/* File name */
X		ap_str(current_file);
X		break;
X	case 'i':	/* Index into list of files */
X		ap_int(curr_ac + 1);
X		break;
X	case 'l':	/* Current line number */
X		n = currline(where);
X		if (n != 0)
X			ap_int(n);
X		else
X			ap_quest();
X		break;
X	case 'L':	/* Final line number */
X		len = ch_length();
X		if (len == NULL_POSITION || len == (POSITION)0 ||
X		    (n = find_linenum(len)) <= 0)
X			ap_quest();
X		else
X			ap_int(n-1);
X		break;
X	case 'm':	/* Number of files */
X		ap_int(ac);
X		break;
X	case 'p':	/* Percent into file */
X		pos = curr_byte(where);
X		len = ch_length();
X		if (pos != NULL_POSITION && len > 0)
X			ap_int((int)(100*pos / len));
X		else
X			ap_quest();
X		break;
X	case 's':	/* Size of file */
X		len = ch_length();
X		if (len != NULL_POSITION)
X			ap_pos(len);
X		else
X			ap_quest();
X		break;
X	case 't':	/* Truncate trailing spaces in the message */
X		while (mp > message && mp[-1] == ' ')
X			mp--;
X		break;
X	case 'x':	/* Name of next file */
X		if (curr_ac + 1 < ac)
X			ap_str(av[curr_ac+1]);
X		else
X			ap_quest();
X		break;
X	}
X}
X
X/*
X * Skip a false conditional.
X * When a false condition is found (either a false IF or the ELSE part 
X * of a true IF), this routine scans the prototype string to decide
X * where to resume parsing the string.
X * We must keep track of nested IFs and skip them properly.
X */
X	static char *
Xskipcond(p)
X	register char *p;
X{
X	register int iflevel;
X
X	/*
X	 * We came in here after processing a ? or :,
X	 * so we start nested one level deep.
X	 */
X	iflevel = 1;
X
X	for (;;) switch (*++p)
X	{
X	case '?':
X		/*
X		 * Start of a nested IF.
X		 */
X		iflevel++;
X		break;
X	case ':':
X		/*
X		 * Else.
X		 * If this matches the IF we came in here with,
X		 * then we're done.
X		 */
X		if (iflevel == 1)
X			return (p);
X		break;
X	case '.':
X		/*
X		 * Endif.
X		 * If this matches the IF we came in here with,
X		 * then we're done.
X		 */
X		if (--iflevel == 0)
X			return (p);
X		break;
X	case '\\':
X		/*
X		 * Backslash escapes the next character.
X		 */
X		++p;
X		break;
X	case '\0':
X		/*
X		 * Whoops.  Hit end of string.
X		 * This is a malformed conditional, but just treat it
X		 * as if all active conditionals ends here.
X		 */
X		return (p-1);
X	}
X	/*NOTREACHED*/
X}
X
X	static char *
Xwherechar(p, wp)
X	char *p;
X	int *wp;
X{
X	switch (*p)
X	{
X	case 'b': case 'l': case 'p':
X		switch (*++p)
X		{
X		case 't':   *wp = TOP;			break;
X		case 'm':   *wp = MIDDLE;		break;
X		case 'b':   *wp = BOTTOM;		break;
X		case 'B':   *wp = BOTTOM_PLUS_ONE;	break;
X		default:    *wp = TOP;			break;
X		}
X	}
X	return (p);
X}
X
X/*
X * Construct a message based on a prototype string.
X */
X	public char *
Xpr_expand(proto, maxwidth)
X	char *proto;
X	int maxwidth;
X{
X	register char *p;
X	register int c;
X	int where;
X
X	mp = message;
X
X	if (*proto == '\0')
X		return ("");
X
X	for (p = proto;  *p != '\0';  p++)
X	{
X		switch (*p)
X		{
X		default:	/* Just put the character in the message */
X			*mp++ = *p;
X			break;
X		case '\\':	/* Backslash escapes the next character */
X			p++;
X			*mp++ = *p;
X			break;
X		case '?':	/* Conditional (IF) */
X			if ((c = *++p) == '\0')
X				--p;
X			else
X			{
X				p = wherechar(p, &where);
X				if (!cond(c, where))
X					p = skipcond(p);
X			}
X			break;
X		case ':':	/* ELSE */
X			p = skipcond(p);
X			break;
X		case '.':	/* ENDIF */
X			break;
X		case '%':	/* Percent escape */
X			if ((c = *++p) == '\0')
X				--p;
X			else
X			{
X				p = wherechar(p, &where);
X				protochar(c, where);
X			}
X			break;
X		}
X	}
X
X	new_file = 0;
X	if (mp == message)
X		return (NULL);
X	*mp = '\0';
X	if (maxwidth > 0 && mp >= message + maxwidth)
X	{
X		/*
X		 * Message is too long.
X		 * Return just the final portion of it.
X		 */
X		return (mp - maxwidth);
X	}
X	return (message);
X}
X
X/*
X * Return a message suitable for printing by the "=" command.
X */
X	public char *
Xeq_message()
X{
X	return (pr_expand(eqproto, 0));
X}
X
X/*
X * Return a prompt.
X * This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
X * If we can't come up with an appropriate prompt, return NULL
X * and the caller will prompt with a colon.
X */
X	public char *
Xpr_string()
X{
X	return (pr_expand(prproto[pr_type], sc_width-so_width-se_width-2));
X}
END_OF_FILE
echo shar: Extracting \"screen.c\"
sed "s/^X//" >'screen.c' <<'END_OF_FILE'
X/*
X * Routines which deal with the characteristics of the terminal.
X * Uses termcap to be as terminal-independent as possible.
X *
X * {{ Someday this should be rewritten to use curses. }}
X */
X
X#include "less.h"
X#if XENIX
X#include <sys/types.h>
X#include <sys/ioctl.h>
X#endif
X
X#if TERMIO
X#include <termio.h>
X#else
X#include <sgtty.h>
X#endif
X
X#ifdef TIOCGWINSZ
X#include <sys/ioctl.h>
X#else
X/*
X * For the Unix PC (ATT 7300 & 3B1):
X * Since WIOCGETD is defined in sys/window.h, we can't use that to decide
X * whether to include sys/window.h.  Use SIGPHONE from sys/signal.h instead.
X */
X#include <sys/signal.h>
X#ifdef SIGPHONE
X#include <sys/window.h>
X#endif
X#endif
X
X/*
X * Strings passed to tputs() to do various terminal functions.
X */
Xstatic char
X	*sc_pad,		/* Pad string */
X	*sc_home,		/* Cursor home */
X	*sc_addline,		/* Add line, scroll down following lines */
X	*sc_lower_left,		/* Cursor to last line, first column */
X	*sc_move,		/* General cursor positioning */
X	*sc_clear,		/* Clear screen */
X	*sc_eol_clear,		/* Clear to end of line */
X	*sc_s_in,		/* Enter standout (highlighted) mode */
X	*sc_s_out,		/* Exit standout mode */
X	*sc_u_in,		/* Enter underline mode */
X	*sc_u_out,		/* Exit underline mode */
X	*sc_b_in,		/* Enter bold mode */
X	*sc_b_out,		/* Exit bold mode */
X	*sc_visual_bell,	/* Visual bell (flash screen) sequence */
X	*sc_backspace,		/* Backspace cursor */
X	*sc_init,		/* Startup terminal initialization */
X	*sc_deinit;		/* Exit terminal de-initialization */
X
Xpublic int auto_wrap;		/* Terminal does \r\n when write past margin */
Xpublic int ignaw;		/* Terminal ignores \n immediately after wrap */
Xpublic int erase_char, kill_char; /* The user's erase and line-kill chars */
Xpublic int sc_width, sc_height;	/* Height & width of screen */
Xpublic int bo_width, be_width;	/* Printing width of boldface sequences */
Xpublic int ul_width, ue_width;	/* Printing width of underline sequences */
Xpublic int so_width, se_width;	/* Printing width of standout sequences */
X
Xstatic char *cheaper();
X
X/*
X * These two variables are sometimes defined in,
X * and needed by, the termcap library.
X * It may be necessary on some systems to declare them extern here.
X */
X/*extern*/ short ospeed;	/* Terminal output baud rate */
X/*extern*/ char PC;		/* Pad character */
X
Xextern int quiet;		/* If VERY_QUIET, use visual bell for bell */
Xextern int know_dumb;		/* Don't complain about a dumb terminal */
Xextern int back_scroll;
Xextern int swindow;
Xextern char *tgetstr();
Xextern char *tgoto();
X
X/*
X * Change terminal to "raw mode", or restore to "normal" mode.
X * "Raw mode" means 
X *	1. An outstanding read will complete on receipt of a single keystroke.
X *	2. Input is not echoed.  
X *	3. On output, \n is mapped to \r\n.
X *	4. \t is NOT expanded into spaces.
X *	5. Signal-causing characters such as ctrl-C (interrupt),
X *	   etc. are NOT disabled.
X * It doesn't matter whether an input \n is mapped to \r, or vice versa.
X */
X	public void
Xraw_mode(on)
X	int on;
X{
X#if TERMIO
X	struct termio s;
X	static struct termio save_term;
X
X	if (on)
X	{
X		/*
X		 * Get terminal modes.
X		 */
X		ioctl(2, TCGETA, &s);
X
X		/*
X		 * Save modes and set certain variables dependent on modes.
X		 */
X		save_term = s;
X		ospeed = s.c_cflag & CBAUD;
X		erase_char = s.c_cc[VERASE];
X		kill_char = s.c_cc[VKILL];
X
X		/*
X		 * Set the modes to the way we want them.
X		 */
X		s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
X		s.c_oflag |=  (OPOST|ONLCR|TAB3);
X		s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
X		s.c_cc[VMIN] = 1;
X		s.c_cc[VTIME] = 0;
X	} else
X	{
X		/*
X		 * Restore saved modes.
X		 */
X		s = save_term;
X	}
X	ioctl(2, TCSETAW, &s);
X#else
X	struct sgttyb s;
X	static struct sgttyb save_term;
X
X	if (on)
X	{
X		/*
X		 * Get terminal modes.
X		 */
X		ioctl(2, TIOCGETP, &s);
X
X		/*
X		 * Save modes and set certain variables dependent on modes.
X		 */
X		save_term = s;
X		ospeed = s.sg_ospeed;
X		erase_char = s.sg_erase;
X		kill_char = s.sg_kill;
X
X		/*
X		 * Set the modes to the way we want them.
X		 */
X		s.sg_flags |= CBREAK;
X		s.sg_flags &= ~(ECHO|XTABS);
X	} else
X	{
X		/*
X		 * Restore saved modes.
X		 */
X		s = save_term;
X	}
X	ioctl(2, TIOCSETN, &s);
X#endif
X}
X
X	static void
Xcannot(s)
X	char *s;
X{
X	char message[100];
X
X	if (know_dumb)
X		/* 
X		 * User knows this is a dumb terminal, so don't tell him.
X		 */
X		return;
X
X	sprintf(message, "WARNING: terminal cannot %s", s);
X	error(message);
X}
X
X/*
X * Get terminal capabilities via termcap.
X */
X	public void
Xget_term()
X{
X	char *sp;
X	register char *t1, *t2;
X	register int hard;
X	char *term;
X#ifdef TIOCGWINSZ
X	struct winsize w;
X#else
X#ifdef WIOCGETD
X	struct uwdata w;
X#endif
X#endif
X	char termbuf[2048];
X
X	static char sbuf[1024];
X
X	extern char *getenv();
X
X	/*
X	 * Find out what kind of terminal this is.
X	 */
X 	if ((term = getenv("TERM")) == NULL)
X 		term = "unknown";
X 	if (tgetent(termbuf, term) <= 0)
X 		strcpy(termbuf, "dumb:co#80:hc:");
X
X	/*
X	 * Get size of the screen.
X	 */
X#ifdef TIOCGWINSZ
X	if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
X		sc_height = w.ws_row;
X	else
X#else
X#ifdef WIOCGETD
X	if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0)
X		sc_height = w.uw_height/w.uw_vs;
X	else
X#endif
X#endif
X 		sc_height = tgetnum("li");
X
X 	hard = (sc_height <= 0 || tgetflag("hc"));
X	if (hard)
X	{
X		/* Oh no, this is a hardcopy terminal. */
X		sc_height = 24;
X	}
X
X	pos_init();
X	if (swindow < 0)
X		swindow = sc_height - 1;
X
X#ifdef TIOCGWINSZ
X 	if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
X		sc_width = w.ws_col;
X	else
X#ifdef WIOCGETD
X	if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0)
X		sc_width = w.uw_width/w.uw_hs;
X	else
X#endif
X#endif
X 		sc_width = tgetnum("co");
X
X 	if (sc_width <= 0)
X  		sc_width = 80;
X
X	auto_wrap = tgetflag("am");
X	ignaw = tgetflag("xn");
X
X	/*
X	 * Assumes termcap variable "sg" is the printing width of:
X	 * the standout sequence, the end standout sequence,
X	 * the underline sequence, the end underline sequence,
X	 * the boldface sequence, and the end boldface sequence.
X	 */
X	if ((so_width = tgetnum("sg")) < 0)
X		so_width = 0;
X	be_width = bo_width = ue_width = ul_width = se_width = so_width;
X
X	/*
X	 * Get various string-valued capabilities.
X	 */
X	sp = sbuf;
X
X	sc_pad = tgetstr("pc", &sp);
X	if (sc_pad != NULL)
X		PC = *sc_pad;
X
X	sc_init = tgetstr("ti", &sp);
X	if (sc_init == NULL)
X		sc_init = "";
X
X	sc_deinit= tgetstr("te", &sp);
X	if (sc_deinit == NULL)
X		sc_deinit = "";
X
X	sc_eol_clear = tgetstr("ce", &sp);
X	if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
X	{
X		cannot("clear to end of line");
X		sc_eol_clear = "";
X	}
X
X	sc_clear = tgetstr("cl", &sp);
X	if (hard || sc_clear == NULL || *sc_clear == '\0')
X	{
X		cannot("clear screen");
X		sc_clear = "\n\n";
X	}
X
X	sc_move = tgetstr("cm", &sp);
X	if (hard || sc_move == NULL || *sc_move == '\0')
X	{
X		/*
X		 * This is not an error here, because we don't 
X		 * always need sc_move.
X		 * We need it only if we don't have home or lower-left.
X		 */
X		sc_move = "";
X	}
X
X	sc_s_in = tgetstr("so", &sp);
X	if (hard || sc_s_in == NULL)
X		sc_s_in = "";
X
X	sc_s_out = tgetstr("se", &sp);
X	if (hard || sc_s_out == NULL)
X		sc_s_out = "";
X
X	sc_u_in = tgetstr("us", &sp);
X	if (hard || sc_u_in == NULL)
X		sc_u_in = sc_s_in;
X
X	sc_u_out = tgetstr("ue", &sp);
X	if (hard || sc_u_out == NULL)
X		sc_u_out = sc_s_out;
X
X	sc_b_in = tgetstr("md", &sp);
X	if (hard || sc_b_in == NULL)
X	{
X		sc_b_in = sc_s_in;
X		sc_b_out = sc_s_out;
X	} else
X	{
X		sc_b_out = tgetstr("me", &sp);
X		if (hard || sc_b_out == NULL)
X			sc_b_out = "";
X	}
X
X	sc_visual_bell = tgetstr("vb", &sp);
X	if (hard || sc_visual_bell == NULL)
X		sc_visual_bell = "";
X
X	if (tgetflag("bs"))
X		sc_backspace = "\b";
X	else
X	{
X		sc_backspace = tgetstr("bc", &sp);
X		if (sc_backspace == NULL || *sc_backspace == '\0')
X			sc_backspace = "\b";
X	}
X
X	/*
X	 * Choose between using "ho" and "cm" ("home" and "cursor move")
X	 * to move the cursor to the upper left corner of the screen.
X	 */
X	t1 = tgetstr("ho", &sp);
X	if (hard || t1 == NULL)
X		t1 = "";
X	if (*sc_move == '\0')
X		t2 = "";
X	else
X	{
X		strcpy(sp, tgoto(sc_move, 0, 0));
X		t2 = sp;
X		sp += strlen(sp) + 1;
X	}
X	sc_home = cheaper(t1, t2, "home cursor", "|\b^");
X
X	/*
X	 * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
X	 * to move the cursor to the lower left corner of the screen.
X	 */
X	t1 = tgetstr("ll", &sp);
X	if (hard || t1 == NULL)
X		t1 = "";
X	if (*sc_move == '\0')
X		t2 = "";
X	else
X	{
X		strcpy(sp, tgoto(sc_move, 0, sc_height-1));
X		t2 = sp;
X		sp += strlen(sp) + 1;
X	}
X	sc_lower_left = cheaper(t1, t2,
X		"move cursor to lower left of screen", "\r");
X
X	/*
X	 * Choose between using "al" or "sr" ("add line" or "scroll reverse")
X	 * to add a line at the top of the screen.
X	 */
X	t1 = tgetstr("al", &sp);
X	if (hard || t1 == NULL)
X		t1 = "";
X	t2 = tgetstr("sr", &sp);
X	if (hard || t2 == NULL)
X		t2 = "";
X	sc_addline = cheaper(t1, t2, "scroll backwards", "");
X	if (*sc_addline == '\0')
X	{
X		/*
X		 * Force repaint on any backward movement.
X		 */
X		back_scroll = 0;
X	}
X}
X
X/*
X * Return the "best" of the two given termcap strings.
X * The best, if both exist, is the one with the lower 
X * cost (see cost() function).
X */
X	static char *
Xcheaper(t1, t2, doit, def)
X	char *t1, *t2;
X	char *doit;
X	char *def;
X{
X	if (*t1 == '\0' && *t2 == '\0')
X	{
X		cannot(doit);
X		return (def);
X	}
X	if (*t1 == '\0')
X		return (t2);
X	if (*t2 == '\0')
X		return (t1);
X	if (cost(t1) < cost(t2))
X		return (t1);
X	return (t2);
X}
X
X/*
X * Return the cost of displaying a termcap string.
X * We use the trick of calling tputs, but as a char printing function
X * we give it inc_costcount, which just increments "costcount".
X * This tells us how many chars would be printed by using this string.
X * {{ Couldn't we just use strlen? }}
X */
Xstatic int costcount;
X
X/*ARGSUSED*/
X	static void
Xinc_costcount(c)
X	int c;
X{
X	costcount++;
X}
X
X	static int
Xcost(t)
X	char *t;
X{
X	costcount = 0;
X	tputs(t, sc_height, inc_costcount);
X	return (costcount);
X}
X
X
X/*
X * Below are the functions which perform all the 
X * terminal-specific screen manipulation.
X */
X
X
X/*
X * Initialize terminal
X */
X	public void
Xinit()
X{
X	tputs(sc_init, sc_height, putchr);
X}
X
X/*
X * Deinitialize terminal
X */
X	public void
Xdeinit()
X{
X	tputs(sc_deinit, sc_height, putchr);
X}
X
X/*
X * Home cursor (move to upper left corner of screen).
X */
X	public void
Xhome()
X{
X	tputs(sc_home, 1, putchr);
X}
X
X/*
X * Add a blank line (called with cursor at home).
X * Should scroll the display down.
X */
X	public void
Xadd_line()
X{
X	tputs(sc_addline, sc_height, putchr);
X}
X
X/*
X * Move cursor to lower left corner of screen.
X */
X	public void
Xlower_left()
X{
X	tputs(sc_lower_left, 1, putchr);
X}
X
X/*
X * Ring the terminal bell.
X */
X	public void
Xbell()
X{
X	if (quiet == VERY_QUIET)
X		vbell();
X	else
X		putchr('\7');
X}
X
X/*
X * Output the "visual bell", if there is one.
X */
X	public void
Xvbell()
X{
X	if (*sc_visual_bell == '\0')
X		return;
X	tputs(sc_visual_bell, sc_height, putchr);
X}
X
X/*
X * Clear the screen.
X */
X	public void
Xclear()
X{
X	tputs(sc_clear, sc_height, putchr);
X}
X
X/*
X * Clear from the cursor to the end of the cursor's line.
X * {{ This must not move the cursor. }}
X */
X	public void
Xclear_eol()
X{
X	tputs(sc_eol_clear, 1, putchr);
X}
X
X/*
X * Begin "standout" (bold, underline, or whatever).
X */
X	public void
Xso_enter()
X{
X	tputs(sc_s_in, 1, putchr);
X}
X
X/*
X * End "standout".
X */
X	public void
Xso_exit()
X{
X	tputs(sc_s_out, 1, putchr);
X}
X
X/*
X * Begin "underline" (hopefully real underlining, 
X * otherwise whatever the terminal provides).
X */
X	public void
Xul_enter()
X{
X	tputs(sc_u_in, 1, putchr);
X}
X
X/*
X * End "underline".
X */
X	public void
Xul_exit()
X{
X	tputs(sc_u_out, 1, putchr);
X}
X
X/*
X * Begin "bold"
X */
X	public void
Xbo_enter()
X{
X	tputs(sc_b_in, 1, putchr);
X}
X
X/*
X * End "bold".
X */
X	public void
Xbo_exit()
X{
X	tputs(sc_b_out, 1, putchr);
X}
X
X/*
X * Erase the character to the left of the cursor 
X * and move the cursor left.
X */
X	public void
Xbackspace()
X{
X	/* 
X	 * Try to erase the previous character by overstriking with a space.
X	 */
X	tputs(sc_backspace, 1, putchr);
X	putchr(' ');
X	tputs(sc_backspace, 1, putchr);
X}
X
X/*
X * Output a plain backspace, without erasing the previous char.
X */
X	public void
Xputbs()
X{
X	tputs(sc_backspace, 1, putchr);
X}
END_OF_FILE
echo shar: Extracting \"signal.c\"
sed "s/^X//" >'signal.c' <<'END_OF_FILE'
X/*
X * Routines dealing with signals.
X *
X * A signal usually merely causes a bit to be set in the "signals" word.
X * At some convenient time, the mainline code checks to see if any
X * signals need processing by calling psignal().
X * If we happen to be reading from a file [in iread()] at the time
X * the signal is received, we call intread to interrupt the iread.
X */
X
X#include "less.h"
X#include <signal.h>
X
X/*
X * "sigs" contains bits indicating signals which need to be processed.
X */
Xpublic int sigs;
X
X#define	S_INTERRUPT	01
X#ifdef SIGTSTP
X#define	S_STOP		02
X#endif
X#if defined(SIGWINCH) || defined(SIGWIND)
X#define S_WINCH		04
X#endif
X
Xextern int sc_width, sc_height;
Xextern int swindow;
Xextern int screen_trashed;
Xextern int lnloop;
Xextern int linenums;
Xextern int scroll;
Xextern int reading;
X
X/*
X * Interrupt signal handler.
X */
X	static HANDLER
Xinterrupt()
X{
X	SIGNAL(SIGINT, interrupt);
X	sigs |= S_INTERRUPT;
X	if (reading)
X		intread();
X}
X
X#ifdef SIGTSTP
X/*
X * "Stop" (^Z) signal handler.
X */
X	static HANDLER
Xstop()
X{
X	SIGNAL(SIGTSTP, stop);
X	sigs |= S_STOP;
X	if (reading)
X		intread();
X}
X#endif
X
X#ifdef SIGWINCH
X/*
X * "Window" change handler
X */
X	public HANDLER
Xwinch()
X{
X	SIGNAL(SIGWINCH, winch);
X	sigs |= S_WINCH;
X	if (reading)
X		intread();
X}
X#else
X#ifdef SIGWIND
X/*
X * "Window" change handler
X */
X	public HANDLER
Xwinch()
X{
X	SIGNAL(SIGWIND, winch);
X	sigs |= S_WINCH;
X	if (reading)
X		intread();
X}
X#endif
X#endif
X
X/*
X * Set up the signal handlers.
X */
X	public void
Xinit_signals(on)
X	int on;
X{
X	if (on)
X	{
X		/*
X		 * Set signal handlers.
X		 */
X		(void) SIGNAL(SIGINT, interrupt);
X#ifdef SIGTSTP
X		(void) SIGNAL(SIGTSTP, stop);
X#endif
X#ifdef SIGWINCH
X		(void) SIGNAL(SIGWINCH, winch);
X#else
X#ifdef SIGWIND
X		(void) SIGNAL(SIGWIND, winch);
X#endif
X#endif
X	} else
X	{
X		/*
X		 * Restore signals to defaults.
X		 */
X		(void) SIGNAL(SIGINT, SIG_DFL);
X#ifdef SIGTSTP
X		(void) SIGNAL(SIGTSTP, SIG_DFL);
X#endif
X#ifdef SIGWINCH
X		(void) SIGNAL(SIGWINCH, SIG_IGN);
X#endif
X#ifdef SIGWIND
X		(void) SIGNAL(SIGWIND, SIG_IGN);
X#endif
X	}
X}
X
X/*
X * Process any signals we have received.
X * A received signal cause a bit to be set in "sigs".
X */
X	public void
Xpsignals()
X{
X	register int tsignals;
X
X	if ((tsignals = sigs) == 0)
X		return;
X	sigs = 0;
X
X#ifdef S_WINCH
X	if (tsignals & S_WINCH)
X	{
X		int old_width, old_height;
X		/*
X		 * Re-execute get_term() to read the new window size.
X		 */
X		old_width = sc_width;
X		old_height = sc_height;
X		swindow = -1;
X		get_term();
X		if (sc_width != old_width || sc_height != old_height)
X		{
X			scroll = (sc_height + 1) / 2;
X			screen_trashed = 1;
X		}
X	}
X#endif
X#ifdef SIGTSTP
X	if (tsignals & S_STOP)
X	{
X		/*
X		 * Clean up the terminal.
X		 */
X#ifdef SIGTTOU
X		SIGNAL(SIGTTOU, SIG_IGN);
X#endif
X		lower_left();
X		clear_eol();
X		deinit();
X		flush();
X		raw_mode(0);
X#ifdef SIGTTOU
X		SIGNAL(SIGTTOU, SIG_DFL);
X#endif
X		SIGNAL(SIGTSTP, SIG_DFL);
X		kill(getpid(), SIGTSTP);
X		/*
X		 * ... Bye bye. ...
X		 * Hopefully we'll be back later and resume here...
X		 * Reset the terminal and arrange to repaint the
X		 * screen when we get back to the main command loop.
X		 */
X		SIGNAL(SIGTSTP, stop);
X		raw_mode(1);
X		init();
X		screen_trashed = 1;
X	}
X#endif
X	if (tsignals & S_INTERRUPT)
X	{
X		bell();
X		/*
X		 * {{ You may wish to replace the bell() with 
X		 *    error("Interrupt"); }}
X		 */
X
X		/*
X		 * If we were interrupted while in the "calculating 
X		 * line numbers" loop, turn off line numbers.
X		 */
X		if (lnloop)
X		{
X			lnloop = 0;
X			if (linenums == 2)
X				screen_trashed = 1;
X			linenums = 0;
X			error("Line numbers turned off");
X		}
X
X	}
X}
END_OF_FILE
echo shar: Extracting \"tags.c\"
sed "s/^X//" >'tags.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include "less.h"
X
X#define	WHITESP(c)	((c)==' ' || (c)=='\t')
X
X#if TAGS
X
Xpublic char *tagfile;
Xpublic char *tagpattern;
X
Xstatic char *tags = "tags";
X
Xextern int linenums;
Xextern int sigs;
X
X/*
X * Find a tag in the "tags" file.
X * Sets "tagfile" to the name of the file containing the tag,
X * and "tagpattern" to the search pattern which should be used
X * to find the tag.
X */
X	public int
Xfindtag(tag)
X	register char *tag;
X{
X	register char *p;
X	register FILE *f;
X	register int taglen;
X	int search_char;
X	static char tline[200];
X
X	if ((f = fopen(tags, "r")) == NULL)
X	{
X		error("No tags file");
X		tagfile = NULL;
X		return;
X	}
X
X	taglen = strlen(tag);
X
X	/*
X	 * Search the tags file for the desired tag.
X	 */
X	while (fgets(tline, sizeof(tline), f) != NULL)
X	{
X		if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen]))
X			continue;
X
X		/*
X		 * Found it.
X		 * The line contains the tag, the filename and the
X		 * pattern, separated by white space.
X		 * The pattern is surrounded by a pair of identical
X		 * search characters.
X		 * Parse the line and extract these parts.
X		 */
X		tagfile = tagpattern = NULL;
X
X		/*
X		 * Skip over the whitespace after the tag name.
X		 */
X		for (p = tline;  !WHITESP(*p) && *p != '\0';  p++)
X			continue;
X		while (WHITESP(*p))
X			p++;
X		if (*p == '\0')
X			/* File name is missing! */
X			continue;
X
X		/*
X		 * Save the file name.
X		 * Skip over the whitespace after the file name.
X		 */
X		tagfile = p;
X		while (!WHITESP(*p) && *p != '\0')
X			p++;
X		*p++ = '\0';
X		while (WHITESP(*p))
X			p++;
X		if (*p == '\0')
X			/* Pattern is missing! */
X			continue;
X
X		/*
X		 * Save the pattern.
X		 * Skip to the end of the pattern.
X		 * Delete the initial "^" and the final "$" from the pattern.
X		 */
X		search_char = *p++;
X		if (*p == '^')
X			p++;
X		tagpattern = p;
X		while (*p != search_char && *p != '\0')
X			p++;
X		if (p[-1] == '$')
X			p--;
X		*p = '\0';
X
X		fclose(f);
X		return;
X	}
X	fclose(f);
X	error("No such tag in tags file");
X	tagfile = NULL;
X}
X
X/*
X * Search for a tag.
X * This is a stripped-down version of search().
X * We don't use search() for several reasons:
X *   -	We don't want to blow away any search string we may have saved.
X *   -	The various regular-expression functions (from different systems:
X *	regcmp vs. re_comp) behave differently in the presence of 
X *	parentheses (which are almost always found in a tag).
X */
X	public int
Xtagsearch()
X{
X	POSITION pos, linepos;
X	int linenum;
X	char *line;
X
X	pos = (POSITION)0;
X	linenum = find_linenum(pos);
X
X	for (;;)
X	{
X		/*
X		 * Get lines until we find a matching one or 
X		 * until we hit end-of-file.
X		 */
X		if (sigs)
X			return (1);
X
X		/*
X		 * Read the next line, and save the 
X		 * starting position of that line in linepos.
X		 */
X		linepos = pos;
X		pos = forw_raw_line(pos, &line);
X		if (linenum != 0)
X			linenum++;
X
X		if (pos == NULL_POSITION)
X		{
X			/*
X			 * We hit EOF without a match.
X			 */
X			error("Tag not found");
X			return (1);
X		}
X
X		/*
X		 * If we're using line numbers, we might as well
X		 * remember the information we have now (the position
X		 * and line number of the current line).
X		 */
X		if (linenums)
X			add_lnum(linenum, pos);
X
X		/*
X		 * Test the line to see if we have a match.
X		 * Use strncmp because the pattern may be
X		 * truncated (in the tags file) if it is too long.
X		 */
X		if (strncmp(tagpattern, line, strlen(tagpattern)) == 0)
X			break;
X	}
X
X	jump_loc(linepos);
X	return (0);
X}
X
X#endif
END_OF_FILE
echo shar: Extracting \"ttyin.c\"
sed "s/^X//" >'ttyin.c' <<'END_OF_FILE'
X/*
X * Routines dealing with getting input from the keyboard (i.e. from the user).
X */
X
X#include "less.h"
X
Xstatic int tty;
X
X/*
X * Open keyboard for input.
X * (Just use file descriptor 2.)
X */
X	public void
Xopen_getchr()
X{
X	tty = 2;
X}
X
X/*
X * Get a character from the keyboard.
X */
X	public int
Xgetchr()
X{
X	char c;
X	int result;
X
X	do
X	{
X		result = iread(tty, &c, sizeof(char));
X		if (result == READ_INTR)
X			return (READ_INTR);
X		if (result < 0)
X		{
X			/*
X			 * Don't call error() here,
X			 * because error calls getchr!
X			 */
X			quit();
X		}
X	} while (result != 1 || c == '\0');
X	return (c);
X}
END_OF_FILE
echo shar: Extracting \"version.c\"
sed "s/^X//" >'version.c' <<'END_OF_FILE'
X/*
X *		less
X *	Copyright (c) 1984,1985,1989  Mark Nudelman
X *
X *	This program may be freely used and/or modified, 
X *	with the following provisions:
X *	1. This notice and the above copyright notice must remain intact.
X *	2. Neither this program, nor any modification of it,
X *	   may be sold for profit without written consent of the author.
X *
X *	-----------------------------------------------------------------
X *	Special note to whoever ported "less" to the Amiga:
X *	If you're going to be vain enough to splash your name on
X *	the screen every time someone runs less, you might at
X *	least credit the author.
X *	-----------------------------------------------------------------
X *
X *	This program is a paginator similar to "more", 
X *	but allows you to move both forward and backward in the file.  
X *	Commands are based on "more" and "vi".
X *
X *	----------------------- CHANGES ---------------------------------
X *
X *	    Allowed use on standard input		1/29/84   markn
X *	    Added E, N, P commands			2/1/84    markn
X *	    Added '=' command, 'stop' signal handling	4/17/84   markn
X *	    Added line folding				4/20/84   markn
X *	v2: Fixed '=' command to use BOTTOM_PLUS_ONE, 
X *	    instead of TOP, added 'p' & 'v' commands	4/27/84   markn
X *	v3: Added -m and -t options, '-' command	5/3/84    markn
X *	v4: Added LESS environment variable		5/3/84    markn
X *	v5: New comments, fixed '-' command slightly	5/3/84    markn
X *	v6: Added -Q, visual bell			5/15/84   markn
X *	v7: Fixed jump_back(n) bug: n should count real
X *	    lines, not folded lines.  Also allow number
X *	    on G command.				5/24/84   markn
X *	v8: Re-do -q and -Q commands			5/30/84   markn
X *	v9: Added "+<cmd>" argument			9/25/84   markn
X *	v10: Fixed bug in -b<n> argument processing	10/10/84  markn
X *	v11: Made error() ring bell if \n not entered.	10/18/84  markn
X *	-----------------------------------------------------------------
X *	v12: Reorganized signal handling and made
X *	     portable to 4.2bsd.			2/13/85   mark
X *	v13: Reword error message for '-' command.	2/16/85   mark
X *	v14: Added -bf and -bp variants of -b.		2/22/85   mark
X *	v15: Miscellaneous changes.			2/25/85   mark
X *	v16: Added -u flag for backspace processing.	3/13/85   mark
X *	v17: Added j and k commands, 
X *		changed -t default.			4/13/85   mark
X *	v18: Rewrote signal handling code.		4/20/85   mark
X *	v19: Got rid of "verbose" eq_message().		5/2/85    mark
X *	     Made search() scroll in some cases.
X *	v20: Fixed screen.c ioctls for System V.	5/21/85   mark
X *	v21: Fixed some first_cmd bugs.			5/23/85   mark
X *	v22: Added support for no RECOMP nor REGCMP.	5/24/85   mark
X * 	v23: Miscellanous changes and prettying up.	5/25/85   mark
X *		Posted to USENET.
X *	-----------------------------------------------------------------
X *      v24: Added ti,te terminal init & de-init       6/3/85 Mike Kersenbrock
X *	v25: Added -U flag, standout mode underlining.	6/8/85    mark
X *	v26: Added -M flag.				6/9/85    mark
X *	     Use underline termcap (us) if it exists.
X *	v27: Renamed some variables to make unique in	6/15/85   mark
X *	     6 chars.  Minor fix to -m.
X *	v28: Fixed right margin bug.			6/28/85   mark
X *	v29: Incorporated M.Rose's changes to signal.c	6/28/85   mark
X *	v30: Fixed stupid bug in argument processing.	6/29/85   mark
X *	v31: Added -p flag, changed repaint algorithm.  7/15/85   mark
X *	     Added kludge for magic cookie terminals.
X *	v32: Added cat_file if output not a tty.	7/16/85   mark
X *	v33: Added -e flag and EDITOR.			7/23/85   mark
X *	v34: Added -s flag.				7/26/85   mark
X *	v35: Rewrote option handling; added option.c.	7/27/85   mark
X *	v36: Fixed -e flag to work if not last file.	7/29/85   mark
X *	v37: Added -x flag.				8/10/85   mark
X *	v38: Changed prompting; created prompt.c.	8/19/85   mark
X *	v39: (Not -p) does not initially clear screen.	8/24/85   mark
X *	v40: Added "skipping" indicator in forw().	8/26/85   mark
X *		Posted to USENET.
X *	-----------------------------------------------------------------
X *	v41: ONLY_RETURN, control char commands,	9/17/85   mark
X *	     faster search, other minor fixes.
X *	v42: Added ++ command line syntax;		9/25/85   mark
X *	     ch_fsize for pipes.
X *	v43: Added -h flag, changed prim.c algorithms.	10/15/85  mark
X *	v44: Made END print in all cases of eof;	10/16/85  mark
X *	     ignore SIGTTOU after receiving SIGTSTP.
X *	v45: Never print backspaces unless -u.		10/16/85  mark
X *	v46: Backwards scroll in jump_loc.		10/24/85  mark
X *	v47: Fixed bug in edit(): *first_cmd==0		10/30/85  mark
X *	v48: Use TIOCSETN instead of TIOCSETP.		11/16/85  mark
X *	     Added marks (m and ' commands).
X *		Posted to USENET.
X *	-----------------------------------------------------------------
X *	v49: Fixed bug: signal didn't clear mcc.	1/9/86    mark
X *	v50: Added ' (quote) to gomark.			1/15/86   mark
X *	v51: Added + cmd, fixed problem if first_cmd
X *	     fails, made g cmd sort of "work" on pipes
X *	     even if bof is no longer buffered.		1/16/86   mark
X *	v52: Made short files work better.		1/17/86   mark
X *	v53: Added -P option.				1/20/86   mark
X *	v54: Changed help to use HELPFILE.		1/20/86   mark
X *	v55: Messages work better if not tty output.	1/23/86   mark
X *	v56: Added -l option.				1/24/86   mark
X *	v57: Fixed -l to get confirmation before
X *	     overwriting an existing file.		1/31/86   mark
X *	v58: Added filename globbing.			8/28/86   mark
X *	v59: Fixed some bugs with very long filenames.	9/15/86   mark
X *	v60: Incorporated changes from Leith (Casey)
X *	     Leedom for boldface and -z option.		9/26/86   mark
X *	v61: Got rid of annoying repaints after ! cmd.	9/26/86   mark
X *		Posted to USENET.
X *	-----------------------------------------------------------------
X *	v62: Added is_directory(); change -z default to
X *	     -1 instead of 24; cat-and-exit if -e and
X *	     file is less than a screenful.		12/23/86  mark
X *	v63: Fixed bug in cat-and-exit if > 1 file.	1/8/87    mark
X *	v64: Changed puts/putstr, putc/putchr, 
X *	     getc/getchr to avoid name conflict with 
X *	     stdio functions.				1/12/87  mark
X *	v65: Allowed '-' command to change NUMBER
X *	     valued options (thanks to Gary Puckering)	1/26/87  mark
X *	v66: Fixed bug: prepaint should use force=1.	2/13/87  mark
X *	v67: Added !! and % expansion to ! command.	2/24/87  mark
X *	v68: Added SIGWINCH and TIOCGWINSZ support;
X *	     changed is_directory to bad_file.
X *	     (thanks to J. Robert Ward)			2/25/87  mark
X *	v69: Added SIGWIND and WIOCGETD (for Unix PC).	2/25/87  mark
X *	v70: Changed help cmd from 'h' to 'H'; better 
X *	     error msgs in bad_file, errno_message.	3/13/87  mark
X *	v71: Changed -p to -c, made triple -c/-C
X *	     for clear-eol like more's -c.		5/11/87  mark
X *	v72: Added -E, -L, use $SHELL in lsystem().	6/26/87  mark
X *	     (thanks to Steve Spearman)
X *	v73: Allow Examine "#" for previous file.	6/26/87  mark
X *		Posted to USENET 8/25/87.
X *	-----------------------------------------------------------------
X *	v74: Fix conflict in EOF symbol with stdio.h,	9/18/87  mark
X *	     Make os.c more portable to BSD.
X *	v75: Fix problems in get_term (thanks to 	9/23/87  mark
X *	     Paul Eggert); new backwards scrolling in
X *	     jump_loc (thanks to Marion Hakanson).
X *	v76: Added -i flag; allow single "!" to		9/23/87  mark
X *	     invoke a shell (thanks to Franco Barber).
X *	v77: Added -n flag and line number support.	9/24/87  mark
X *	v78: Fixed problem with prompts longer than	9/25/87  mark
X *	     the screen width.	
X *	v79: Added the _ command.			9/29/87  mark
X *	v80: Allow signal to break out of linenum scan.	10/6/87  mark
X *	v81: Allow -b to be changed from within less.	10/6/87  mark
X *	v82: Add cmd_decode to use a table for key	10/7/87  mark
X *	     binding (thanks to David Nason).
X *	v83: Allow .less file for user-defined keys.	10/9/87  mark
X *	v84: Fix -e/-E problems (thanks to Felix Lee).	10/11/87 mark
X *	v85: Search now keeps track of line numbers.	10/15/87 mark
X *	v86: Added -B option and autobuf; fixed		10/20/87 mark
X *	     "pipe error" bug.
X *	v87: Fix bug re BSD signals while reading file.	3/1/88   mark
X *	v88: Use new format for -P option (thanks to	3/12/88  mark
X *	     der Mouse), allow "+-c" without message,
X *	     fix bug re BSD hangup.
X *	v89: Turn off line numbers if linenum scan	3/18/88  mark
X *	     is interrupted.
X *	v90: Allow -P from within less.			3/30/88  mark
X *	v91: Added tags file support (new -t option)	3/30/88  mark
X *	     (thanks to Brian Campbell).
X *	v92: Added -+option syntax.			4/4/88   mark
X *	v93: Add support for slow input (thanks to	4/11/88  mark
X *	     Joe Orost & apologies for taking almost
X *	     3 years to get this in!)
X *	v94: Redo reading/signal stuff.			4/11/88  mark
X *	v95: Repaint screen better after signal.	4/20/88  mark
X *	v96: Add /! and ?! commands.			4/21/88  mark
X *	v97: Allow -l/-L from within less.		5/17/88  mark
X *	     Eliminate some static arrays (use calloc).
X *		Posted to USENET.
X *	-----------------------------------------------------------------
X *	v98: Fix incorrect calloc call; uninitialized	10/14/88 mark
X *	     var in exec_mca; core dump on unknown TERM.
X *	     Make v cmd work if past last line of file.
X *	     Fix some signal bugs.
X *	v99: Allow space between -X and string,		10/29/88 mark
X *	     when X is a string-valued option.
X *	v100: Fix globbing bug when $SHELL not set;	1/5/89   mark
X *	      allow spaces after -t command.
X *	v101: Fix problem with long (truncated) lines	1/6/89   mark
X *	      in tags file (thanks to Neil Dixon).
X *	v102: Fix bug with E# when no prev file;	1/6/89   mark
X *	      allow spaces after -l command.
X *	v103: Add -N, -f and -? options.  Add z and w	3/14/89  mark
X *	      commands.  Add %L for prompt strings.
X *	v104: Added EDITPROTO.				3/16/89  mark
X *	v105: Fix bug in find_linenum which cached	3/20/89  mark
X *	      incorrectly on long lines.
X *	v106: Added -k option and multiple lesskey      3/31/89  mark
X *	      files.
X *	v107: Add 8-bit char support and -g option.	4/27/89  mark
X *	      Split option code into 3 files.
X *	v108: Allocate position table dynamically       5/5/89   mark
X *	      (thanks to Paul Eggert); change % command
X *	      from "percent" to vi-style brace finder.
X *	v109: Added ESC-% command, split prim.c.	5/10/89  mark
X *	v110: Fixed bug in + option; fixed repaint bug	5/24/89  mark
X *	      under Sun windows (thanks to Paul Eggert).
X *	v111: Generalized # and % expansion; use 	5/25/89  mark
X *	      calloc for some error messages.
X *	v112: Get rid of ESC-%, add {}()[] commands.	5/30/89  mark
X *	v113: Optimize lseeks (thanks to Paul Eggert).	5/31/89  mark
X *	v114: Added ESC-/ and ESC-/! commands.		7/25/89  mark
X *	v115: Added ESC-n command.			7/26/89  mark
X *	v116: Added find_pos to optimize g command.	7/31/89  mark
X *	v117: Change -f option to -r.			8/1/89   mark
X *	v118: Save positions for all previous files,	8/2/89   mark
X *	      not just the immediately previous one.
X *	v119: Save marks across file boundaries.	8/7/89   mark
X *	      Add file handle stuff.
X *	v120: Add :ta command.				8/11/89  mark
X *	v121: Add -f option.				8/16/89  mark
X *	v122: Fix performance with many buffers.	8/30/89  mark
X *	v123: Verbose prompts for string options.	8/31/89  mark
X */
X
Xchar version[] = "@(#) less  version 123";
END_OF_FILE



More information about the Alt.sources mailing list