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