home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!ogicse!emory!sol.ctr.columbia.edu!howland.reston.ans.net!europa.asd.contel.com!wlbr!sms
- From: sms@WLV.IIPO.GTEGSC.COM (Steven M. Schultz)
- Newsgroups: comp.bugs.2bsd
- Subject: 'less' for 2.11BSD (#101)
- Message-ID: <1993Jan25.182911.19307@wlbr.iipo.gtegsc.com>
- Date: 25 Jan 93 18:29:11 GMT
- Article-I.D.: wlbr.1993Jan25.182911.19307
- Sender: news@wlbr.iipo.gtegsc.com (news)
- Organization: GTE Government Systems
- Lines: 6344
- Nntp-Posting-Host: wlv.iipo.gtegsc.com
-
- Subject: 'less' for 2.11BSD (#101)
- Index: local/less 2.11BSD
-
- Description:
- A new program being installed in the source tree.
-
- Thanks to Paul Taylor (taylor@oswego.oswego.edu) for doing the port.
-
- Repeat-By:
- N/A.
-
- Fix:
- Cut at the indicated line, unpack the shar file, cd /usr/src/local/less
- and "make all; make install".
- ================================cut here=====================================
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # /usr/src/local/less
- # This archive created: Mon Jan 25 09:27:56 1993
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test ! -d '/usr/src/local/less'
- then
- mkdir '/usr/src/local/less'
- fi
- cd '/usr/src/local/less'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- XThis is the distribution of "less", a paginator similar to "more" or "pg".
- XThe manual page is in less.man (nroff source in less.nro).
- X
- XINSTALLATION:
- X
- X1. Move the distributed source to its own directory and
- X unpack it by running "sh" on the distribution file,
- X if you have not already done so.
- X
- X2. Type "install" and answer the questions it asks.
- X This will generate a makefile.
- X
- X If you choose not to include some features in your version,
- X you may wish to edit the manual page less.nro and/or less.man
- X to remove the references to the appropriate commands or options.
- X
- X (NOTE: there are some pre-generated makefiles for
- X various systems, named makefile.sys5, makefile.bsd41,
- X etc. which may be used if you wish.)
- X
- X3. It is a good idea to look over the generated makefile
- X and make sure it looks ok.
- X
- X4. Type "make" and watch the fun.
- X
- X5. If the make succeeds, it will generate a program "less"
- X in your current directory. Test the generated program.
- X
- X6. When satisfied that it works, if you wish to install it
- X in a public place, type "make install".
- X
- XIf you have any problems building or running "less",
- Xsuggestions, complaints, etc., you may mail to the
- Xauthor via USENET at:
- X tektronix!nscpdc!convgt!mark
- X or ihnp4!nsc!nscpdc!convgt!mark
- X
- XNote to hackers: comments noting possible improvements are enclosed
- Xin double curly brackets {{ like this }}.
- SHAR_EOF
- fi
- if test -f 'ch.c'
- then
- echo shar: "will not over-write existing file 'ch.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'ch.c'
- X/*
- X * Low level character input from the input file.
- X * We use these special purpose routines which optimize moving
- X * both forward and backward from the current read pointer.
- X */
- X
- X#include "less.h"
- X
- Xpublic int file = -1; /* File descriptor of the input file */
- X
- X/*
- X * Pool of buffers holding the most recently used blocks of the input file.
- X */
- X#define BUFSIZ 1024
- Xstruct buf {
- X struct buf *next, *prev;
- X long block;
- X char data[BUFSIZ];
- X};
- Xstatic struct buf *bufs = NULL;
- Xpublic int nbufs;
- X
- X/*
- X * The buffer pool is kept as a doubly-linked circular list,
- X * in order from most- to least-recently used.
- X * The circular list is anchored by buf_anchor.
- X */
- Xstatic struct {
- X struct buf *next, *prev;
- X} buf_anchor;
- X#define END_OF_CHAIN ((struct buf *)&buf_anchor)
- X#define buf_head buf_anchor.next
- X#define buf_tail buf_anchor.prev
- X
- X/*
- X * If we fail to allocate enough memory for buffers, we try to limp
- X * along with a minimum number of buffers.
- X */
- X#define DEF_NBUFS 2 /* Minimum number of buffers */
- X
- Xextern int clean_data;
- Xextern int ispipe;
- Xextern int sigs;
- X
- X#if LOGFILE
- Xextern int logfile;
- X#endif
- X
- X/*
- X * Current position in file.
- X * Stored as a block number and an offset into the block.
- X */
- Xstatic long ch_block;
- Xstatic int ch_offset;
- X
- X/*
- X * Length of file, needed if input is a pipe.
- X */
- Xstatic POSITION ch_fsize;
- X
- X/*
- X * Largest block number read if input is standard input (a pipe).
- X */
- Xstatic long last_piped_block;
- X
- X/*
- X * Get the character pointed to by the read pointer.
- X * ch_get() is a macro which is more efficient to call
- X * than fch_get (the function), in the usual case
- X * that the block desired is at the head of the chain.
- X */
- X#define ch_get() ((buf_head->block == ch_block) ? \
- X buf_head->data[ch_offset] : fch_get())
- X static int
- Xfch_get()
- X{
- X register struct buf *bp;
- X register int n;
- X register int end;
- X POSITION pos;
- X
- X /*
- X * Look for a buffer holding the desired block.
- X */
- X for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
- X if (bp->block == ch_block)
- X goto found;
- X /*
- X * Block is not in a buffer.
- X * Take the least recently used buffer
- X * and read the desired block into it.
- X */
- X bp = buf_tail;
- X bp->block = ch_block;
- X pos = ch_block * BUFSIZ;
- X if (ispipe)
- X {
- X /*
- X * The block requested should be one more than
- X * the last block read.
- X */
- X if (ch_block != ++last_piped_block)
- X {
- X /* This "should not happen". */
- X char message[80];
- X sprintf(message, "Pipe error: last %ld, want %ld\n",
- X (long)last_piped_block-1, (long)ch_block);
- X error(message);
- X quit();
- X }
- X } else
- X lseek(file, pos, 0);
- X
- X /*
- X * Read the block. This may take several reads if the input
- X * is coming from standard input, due to the nature of pipes.
- X */
- X end = 0;
- X while ((n = read(file, &bp->data[end], BUFSIZ-end)) > 0)
- X if ((end += n) >= BUFSIZ)
- X break;
- X
- X if (n < 0)
- X {
- X error("read error");
- X quit();
- X }
- X
- X#if LOGFILE
- X /*
- X * If we have a log file, write this block to it.
- X */
- X if (logfile >= 0 && end > 0)
- X write(logfile, bp->data, end);
- X#endif
- X
- X /*
- X * Set an EOF marker in the buffered data itself.
- X * Then ensure the data is "clean": there are no
- X * extra EOF chars in the data and that the "meta"
- X * bit (the 0200 bit) is reset in each char.
- X */
- X if (end < BUFSIZ)
- X {
- X ch_fsize = pos + end;
- X bp->data[end] = EOF;
- X }
- X
- X if (!clean_data)
- X while (--end >= 0)
- X {
- X bp->data[end] &= 0177;
- X if (bp->data[end] == EOF)
- X bp->data[end] = '@';
- X }
- X
- X found:
- X /* if (buf_head != bp) {this is guaranteed by the ch_get macro} */
- X {
- X /*
- X * Move the buffer to the head of the buffer chain.
- X * This orders the buffer chain, most- to least-recently used.
- X */
- X bp->next->prev = bp->prev;
- X bp->prev->next = bp->next;
- X
- X bp->next = buf_head;
- X bp->prev = END_OF_CHAIN;
- X buf_head->prev = bp;
- X buf_head = bp;
- X }
- X return (bp->data[ch_offset]);
- X}
- X
- X#if LOGFILE
- X/*
- X * Close the logfile.
- X * If we haven't read all of standard input into it, do that now.
- X */
- X public void
- Xend_logfile()
- X{
- X static int tried;
- X
- X if (logfile < 0)
- X return;
- X if (!tried && ch_fsize == NULL_POSITION)
- X {
- X tried = 1;
- X lower_left();
- X clear_eol();
- X so_enter();
- X puts("finishing logfile... (interrupt to abort)");
- X so_exit();
- X flush();
- X while (sigs == 0 && ch_forw_get() != EOF)
- X ;
- X }
- X close(logfile);
- X logfile = -1;
- X}
- X#endif
- X
- X/*
- X * Determine if a specific block is currently in one of the buffers.
- X */
- X static int
- Xbuffered(block)
- X long block;
- X{
- X register struct buf *bp;
- X
- X for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
- X if (bp->block == block)
- X return (1);
- X return (0);
- X}
- X
- X/*
- X * Seek to a specified position in the file.
- X * Return 0 if successful, non-zero if can't seek there.
- X */
- X public int
- Xch_seek(pos)
- X register POSITION pos;
- X{
- X long new_block;
- X
- X new_block = pos / BUFSIZ;
- X if (!ispipe || new_block == last_piped_block + 1 || buffered(new_block))
- X {
- X /*
- X * Set read pointer.
- X */
- X ch_block = new_block;
- X ch_offset = pos % BUFSIZ;
- X return (0);
- X }
- X return (1);
- X}
- X
- X/*
- X * Seek to the end of the file.
- X */
- X public int
- Xch_end_seek()
- X{
- X if (ispipe)
- X {
- X /*
- X * Do it the slow way: read till end of data.
- X */
- X while (ch_forw_get() != EOF)
- X ;
- X } else
- X {
- X (void) ch_seek((POSITION)(lseek(file, (off_t)0, 2)));
- X }
- X return (0);
- X}
- X
- X/*
- X * Seek to the beginning of the file, or as close to it as we can get.
- X * We may not be able to seek there if input is a pipe and the
- X * beginning of the pipe is no longer buffered.
- X */
- X public int
- Xch_beg_seek()
- X{
- X register struct buf *bp, *firstbp;
- X
- X /*
- X * Try a plain ch_seek first.
- X */
- X if (ch_seek((POSITION)0) == 0)
- X return (0);
- X
- X /*
- X * Can't get to position 0.
- X * Look thru the buffers for the one closest to position 0.
- X */
- X firstbp = bp = buf_head;
- X if (bp == END_OF_CHAIN)
- X return (1);
- X while ((bp = bp->next) != END_OF_CHAIN)
- X if (bp->block < firstbp->block)
- X firstbp = bp;
- X ch_block = firstbp->block;
- X ch_offset = 0;
- X return (0);
- X}
- X
- X/*
- X * Return the length of the file, if known.
- X */
- X public POSITION
- Xch_length()
- X{
- X if (ispipe)
- X return (ch_fsize);
- X return ((POSITION)(lseek(file, (off_t)0, 2)));
- X}
- X
- X/*
- X * Return the current position in the file.
- X */
- X public POSITION
- Xch_tell()
- X{
- X return (ch_block * BUFSIZ + ch_offset);
- X}
- X
- X/*
- X * Get the current char and post-increment the read pointer.
- X */
- X public int
- Xch_forw_get()
- X{
- X register int c;
- X
- X c = ch_get();
- X if (c != EOF && ++ch_offset >= BUFSIZ)
- X {
- X ch_offset = 0;
- X ch_block ++;
- X }
- X return (c);
- X}
- X
- X/*
- X * Pre-decrement the read pointer and get the new current char.
- X */
- X public int
- Xch_back_get()
- X{
- X register int c;
- X
- X if (--ch_offset < 0)
- X {
- X if (ch_block <= 0 || (ispipe && !buffered(ch_block-1)))
- X {
- X ch_offset = 0;
- X return (EOF);
- X }
- X ch_offset = BUFSIZ - 1;
- X ch_block--;
- X }
- X c = ch_get();
- X return (c);
- X}
- X
- X/*
- X * Initialize the buffer pool to all empty.
- X * Caller suggests that we use want_nbufs buffers.
- X */
- X public void
- Xch_init(want_nbufs)
- X int want_nbufs;
- X{
- X register struct buf *bp;
- X char *calloc();
- X
- X if (nbufs < want_nbufs)
- X {
- X /*
- X * We don't have enough buffers.
- X * Free what we have (if any) and allocate some new ones.
- X */
- X if (bufs != NULL)
- X free((char *)bufs);
- X bufs = (struct buf *) calloc(want_nbufs, sizeof(struct buf));
- X nbufs = want_nbufs;
- X if (bufs == NULL)
- X {
- X /*
- X * Couldn't get that many.
- X * Try for a small default number of buffers.
- X */
- X char message[80];
- X sprintf(message,
- X "Cannot allocate %d buffers. Using %d buffers.",
- X nbufs, DEF_NBUFS);
- X error(message);
- X bufs = (struct buf *) calloc(DEF_NBUFS, sizeof(struct buf));
- X nbufs = DEF_NBUFS;
- X if (bufs == NULL)
- X {
- X /*
- X * Couldn't even get the smaller number of bufs.
- X * Something is wrong here, don't continue.
- X */
- X sprintf(message,
- X "Cannot even allocate %d buffers! Quitting.",
- X DEF_NBUFS);
- X error(message);
- X quit();
- X /*NOTREACHED*/
- X }
- X }
- X }
- X
- X /*
- X * Initialize the buffers to empty.
- X * Set up the circular list.
- X */
- X for (bp = &bufs[0]; bp < &bufs[nbufs]; bp++)
- X {
- X bp->next = bp + 1;
- X bp->prev = bp - 1;
- X bp->block = (long)(-1);
- X }
- X bufs[0].prev = bufs[nbufs-1].next = END_OF_CHAIN;
- X buf_head = &bufs[0];
- X buf_tail = &bufs[nbufs-1];
- X last_piped_block = -1;
- X ch_fsize = NULL_POSITION;
- X (void) ch_seek((POSITION)0);
- X}
- SHAR_EOF
- fi
- if test -f 'command.c'
- then
- echo shar: "will not over-write existing file 'command.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'command.c'
- X/*
- X * User-level command processor.
- X */
- X
- X#include "less.h"
- X#include "position.h"
- X#include <setjmp.h>
- X
- Xextern jmp_buf main_loop;
- Xextern int erase_char, kill_char;
- Xextern int pr_type;
- Xextern int sigs;
- Xextern int ispipe;
- Xextern int quit_at_eof;
- Xextern int hit_eof;
- Xextern int sc_width, sc_height;
- Xextern int sc_window;
- Xextern char *first_cmd;
- Xextern char *every_first_cmd;
- Xextern char version[];
- Xextern char current_file[];
- Xextern char *editor;
- X
- Xstatic char cmdbuf[90]; /* Buffer for holding a multi-char command */
- Xstatic char *cp; /* Pointer into cmdbuf */
- Xstatic int cmd_col; /* Current column of the multi-char command */
- Xstatic char mcc; /* The multi-char command letter (e.g. '/') */
- Xstatic char last_mcc; /* The previous mcc */
- Xstatic int screen_trashed; /* The screen has been overwritten */
- X
- X/*
- X * Reset command buffer (to empty).
- X */
- Xcmd_reset()
- X{
- X cp = cmdbuf;
- X}
- X
- X/*
- X * Backspace in command buffer.
- X */
- X static int
- Xcmd_erase()
- X{
- X if (cp == cmdbuf)
- X /*
- X * Backspace past beginning of the string:
- X * this usually means abort the command.
- X */
- X return (1);
- X
- X if (control_char(*--cp))
- X {
- X /*
- X * Erase an extra character, for the carat.
- X */
- X backspace();
- X cmd_col--;
- X }
- X backspace();
- X cmd_col--;
- X return (0);
- X}
- X
- X/*
- X * Set up the display to start a new multi-character command.
- X */
- Xstart_mcc(c)
- X int c;
- X{
- X mcc = c;
- X lower_left();
- X clear_eol();
- X putc(mcc);
- X cmd_col = 1;
- X}
- X
- X/*
- X * Process a single character of a multi-character command, such as
- X * a number, or the pattern of a search command.
- X */
- X static int
- Xcmd_char(c)
- X int c;
- X{
- X if (c == erase_char)
- X {
- X if (cmd_erase())
- X return (1);
- X } else if (c == kill_char)
- X {
- X /* {{ Could do this faster, but who cares? }} */
- X while (cmd_erase() == 0)
- X ;
- X } else
- X {
- X /*
- X * Append the character to the string,
- X * if there is room in the buffer and on the screen.
- X */
- X if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3)
- X {
- X *cp++ = c;
- X if (control_char(c))
- X {
- X putc('^');
- X cmd_col++;
- X c = carat_char(c);
- X }
- X putc(c);
- X cmd_col++;
- X } else
- X bell();
- X }
- X return (0);
- X}
- X
- X/*
- X * Return the number currently in the command buffer.
- X */
- X static int
- Xcmd_int()
- X{
- X *cp = '\0';
- X cp = cmdbuf;
- X return (atoi(cmdbuf));
- X}
- X
- X/*
- X * Move the cursor to lower left before executing a command.
- X * This looks nicer if the command takes a long time before
- X * updating the screen.
- X */
- X static void
- Xcmd_exec()
- X{
- X lower_left();
- X flush();
- X}
- X
- X/*
- X * Display the appropriate prompt.
- X */
- X static void
- Xprompt()
- X{
- X register char *p;
- X
- X if (first_cmd != NULL && *first_cmd != '\0')
- X /*
- X * No prompt necessary if commands are from first_cmd
- X * rather than from the user.
- X */
- X return;
- X
- X /*
- X * If nothing is displayed yet, display starting from line 1.
- X */
- X if (position(TOP) == NULL_POSITION)
- X jump_back(1);
- X else if (screen_trashed)
- X repaint();
- X screen_trashed = 0;
- X
- X /*
- X * Select the proper prompt and display it.
- X */
- X lower_left();
- X clear_eol();
- X p = pr_string();
- X if (p == NULL)
- X putc(':');
- X else
- X {
- X so_enter();
- X puts(p);
- X so_exit();
- X }
- X}
- X
- X/*
- X * Get command character.
- X * The character normally comes from the keyboard,
- X * but may come from the "first_cmd" string.
- X */
- X static int
- Xgetcc()
- X{
- X if (first_cmd == NULL)
- X return (getc());
- X
- X if (*first_cmd == '\0')
- X {
- X /*
- X * Reached end of first_cmd input.
- X */
- X first_cmd = NULL;
- X if (cp > cmdbuf && position(TOP) == NULL_POSITION)
- X {
- X /*
- X * Command is incomplete, so try to complete it.
- X * There are only two cases:
- X * 1. We have "/string" but no newline. Add the \n.
- X * 2. We have a number but no command. Treat as #g.
- X * (This is all pretty hokey.)
- X */
- X if (mcc != ':')
- X /* Not a number; must be search string */
- X return ('\n');
- X else
- X /* A number; append a 'g' */
- X return ('g');
- X }
- X return (getc());
- X }
- X return (*first_cmd++);
- X}
- X
- X/*
- X * Main command processor.
- X * Accept and execute commands until a quit command, then return.
- X */
- X public void
- Xcommands()
- X{
- X register int c;
- X register int n;
- X register int scroll = 10;
- X
- X last_mcc = 0;
- X setjmp(main_loop);
- X mcc = 0;
- X
- X for (;;)
- X {
- X /*
- X * Display prompt and accept a character.
- X */
- X psignals(); /* See if any signals need processing */
- X
- X if (quit_at_eof && hit_eof > 1)
- X /*
- X * After hitting end-of-file for the second time,
- X * automatically advance to the next file.
- X * If there are no more files, quit.
- X */
- X next_file(1);
- X
- X cmd_reset();
- X prompt();
- X c = getcc();
- X
- X again:
- X if (sigs)
- X continue;
- X
- X if (mcc)
- X {
- X /*
- X * We are in a multi-character command.
- X * All chars until newline go into the command buffer.
- X * (Note that mcc == ':' is a special case that
- X * means a number is being entered.)
- X */
- X if (mcc != ':' && (c == '\n' || c == '\r'))
- X {
- X char *p;
- X static char fcbuf[100];
- X
- X /*
- X * Execute the command.
- X */
- X *cp = '\0';
- X cmd_exec();
- X switch (mcc)
- X {
- X case '/': case '?':
- X search(mcc, cmdbuf, n);
- X break;
- X case '+':
- X for (p = cmdbuf; *p == '+' || *p == ' '; p++) ;
- X if (*p == '\0')
- X every_first_cmd = NULL;
- X else
- X {
- X strtcpy(fcbuf, p, sizeof(fcbuf));
- X every_first_cmd = fcbuf;
- X }
- X break;
- X case 'E':
- X /*
- X * Ignore leading spaces
- X * in the filename.
- X */
- X for (p = cmdbuf; *p == ' '; p++) ;
- X edit(glob(p));
- X break;
- X#if SHELL_ESCAPE
- X case '!':
- X lsystem(cmdbuf);
- X screen_trashed = 1;
- X error("!done");
- X break;
- X#endif
- X }
- X mcc = 0;
- X } else
- X {
- X if (mcc == ':' && (c < '0' || c > '9') &&
- X c != erase_char && c != kill_char)
- X {
- X /*
- X * This is not part of the number
- X * we were entering. Process
- X * it as a regular character.
- X */
- X mcc = 0;
- X goto again;
- X }
- X
- X /*
- X * Append the char to the command buffer.
- X */
- X if (cmd_char(c))
- X {
- X /* Abort the multi-char command. */
- X mcc = 0;
- X continue;
- X }
- X c = getcc();
- X goto again;
- X }
- X } else switch (c)
- X {
- X case '0': case '1': case '2': case '3': case '4':
- X case '5': case '6': case '7': case '8': case '9':
- X /*
- X * First digit of a number.
- X */
- X start_mcc(':');
- X goto again;
- X
- X case 'f':
- X case ' ':
- X case CONTROL('F'):
- X /*
- X * Forward one screen.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = sc_window;
- X forward(n, 1);
- X break;
- X
- X case 'b':
- X case CONTROL('B'):
- X /*
- X * Backward one screen.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = sc_window;
- X backward(n, 1);
- X break;
- X
- X case 'e':
- X case 'j':
- X case '\r':
- X case '\n':
- X case CONTROL('E'):
- X /*
- X * Forward N (default 1) line.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X forward(n, 0);
- X break;
- X
- X case 'y':
- X case 'k':
- X case CONTROL('K'):
- X case CONTROL('Y'):
- X /*
- X * Backward N (default 1) line.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X backward(n, 0);
- X break;
- X
- X case 'd':
- X case CONTROL('D'):
- X /*
- X * Forward N lines
- X * (default same as last 'd' or 'u' command).
- X */
- X n = cmd_int();
- X if (n > 0)
- X scroll = n;
- X forward(scroll, 0);
- X break;
- X
- X case 'u':
- X case CONTROL('U'):
- X /*
- X * Forward N lines
- X * (default same as last 'd' or 'u' command).
- X */
- X n = cmd_int();
- X if (n > 0)
- X scroll = n;
- X backward(scroll, 0);
- X break;
- X
- X case 'R':
- X /*
- X * Flush buffers, then repaint screen.
- X * Don't flush the buffers on a pipe!
- X */
- X if (!ispipe)
- X ch_init(0);
- X /* Fall thru */
- X case 'r':
- X case CONTROL('R'):
- X case CONTROL('L'):
- X /*
- X * Repaint screen.
- X */
- X repaint();
- X break;
- X
- X case 'g':
- X /*
- X * Go to line N, default beginning of file.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X cmd_exec();
- X jump_back(n);
- X break;
- X
- X case 'p':
- X case '%':
- X /*
- X * Go to a specified percentage into the file.
- X */
- X n = cmd_int();
- X if (n < 0)
- X n = 0;
- X if (n > 100)
- X n = 100;
- X cmd_exec();
- X jump_percent(n);
- X break;
- X
- X case 'G':
- X /*
- X * Go to line N, default end of file.
- X */
- X n = cmd_int();
- X cmd_exec();
- X if (n <= 0)
- X jump_forw();
- X else
- X jump_back(n);
- X break;
- X
- X case '=':
- X case CONTROL('G'):
- X /*
- X * Print file name, etc.
- X */
- X error(eq_message());
- X break;
- X
- X case 'V':
- X /*
- X * Print version number, without the "@(#)".
- X */
- X error(version+4);
- X break;
- X
- X case 'q':
- X /*
- X * Exit.
- X */
- X /*setjmp(main_loop);*/
- X quit();
- X
- X case '/':
- X case '?':
- X /*
- X * Search for a pattern.
- X * Accept chars of the pattern until \n.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X start_mcc(c);
- X last_mcc = c;
- X c = getcc();
- X goto again;
- X
- X case 'n':
- X /*
- X * Repeat previous search.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X start_mcc(last_mcc);
- X cmd_exec();
- X search(mcc, (char *)NULL, n);
- X mcc = 0;
- X break;
- X
- X case 'h':
- X /*
- X * Help.
- X */
- X lower_left();
- X clear_eol();
- X puts("help");
- X cmd_exec();
- X help();
- X screen_trashed = 1;
- X break;
- X
- X case 'E':
- X /*
- X * Edit a new file. Get the filename.
- X */
- X cmd_reset();
- X start_mcc('E');
- X puts("xamine: "); /* This looks nicer */
- X cmd_col += 8;
- X c = getcc();
- X goto again;
- X
- X case '!':
- X#if SHELL_ESCAPE
- X /*
- X * Shell escape.
- X */
- X cmd_reset();
- X start_mcc('!');
- X c = getcc();
- X goto again;
- X#else
- X error("Command not available");
- X break;
- X#endif
- X
- X case 'v':
- X#if EDITOR
- X if (ispipe)
- X {
- X error("Cannot edit standard input");
- X break;
- X }
- X sprintf(cmdbuf, "%s %s", editor, current_file);
- X lsystem(cmdbuf);
- X ch_init(0);
- X screen_trashed = 1;
- X break;
- X#else
- X error("Command not available");
- X break;
- X#endif
- X
- X case 'N':
- X /*
- X * Examine next file.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X next_file(n);
- X break;
- X
- X case 'P':
- X /*
- X * Examine previous file.
- X */
- X n = cmd_int();
- X if (n <= 0)
- X n = 1;
- X prev_file(n);
- X break;
- X
- X case '-':
- X /*
- X * Toggle a flag setting.
- X */
- X start_mcc('-');
- X c = getcc();
- X mcc = 0;
- X if (c == erase_char || c == kill_char)
- X break;
- X toggle_option(c);
- X break;
- X
- X case '+':
- X cmd_reset();
- X start_mcc('+');
- X c = getcc();
- X goto again;
- X
- X case 'm':
- X /*
- X * Set a mark.
- X */
- X lower_left();
- X clear_eol();
- X puts("mark: ");
- X c = getcc();
- X if (c == erase_char || c == kill_char)
- X break;
- X setmark(c);
- X break;
- X
- X case '\'':
- X /*
- X * Go to a mark.
- X */
- X lower_left();
- X clear_eol();
- X puts("goto mark: ");
- X c = getcc();
- X if (c == erase_char || c == kill_char)
- X break;
- X gomark(c);
- X break;
- X
- X default:
- X bell();
- X break;
- X }
- X }
- X}
- SHAR_EOF
- fi
- if test -f 'funcs.h'
- then
- echo shar: "will not over-write existing file 'funcs.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'funcs.h'
- X public void edit ();
- X public void next_file ();
- X public void prev_file ();
- X public void quit ();
- X public void init_option ();
- X public void toggle_option ();
- X public void scan_option ();
- X public void forward ();
- X public void backward ();
- X public void repaint ();
- X public void jump_forw ();
- X public void jump_back ();
- X public void jump_percent ();
- X public void jump_loc ();
- X public void init_mark ();
- X public void setmark ();
- X public void lastmark ();
- X public void gomark ();
- X public int get_back_scroll ();
- X public void search ();
- X public void end_logfile ();
- X public int ch_seek ();
- X public int ch_end_seek ();
- X public int ch_beg_seek ();
- X public POSITION ch_length ();
- X public POSITION ch_tell ();
- X public int ch_forw_get ();
- X public int ch_back_get ();
- X public void ch_init ();
- X public POSITION position ();
- X public void add_forw_pos ();
- X public void add_back_pos ();
- X public void pos_clear ();
- X public int onscreen ();
- X public POSITION forw_line ();
- X public POSITION back_line ();
- X public void put_line ();
- X public int control_char ();
- X public int carat_char ();
- X public void flush ();
- X public void dropout ();
- X public void putc ();
- X public void puts ();
- X public void error ();
- X public int error_width ();
- X public void raw_mode ();
- X public void get_term ();
- X public void init ();
- X public void deinit ();
- X public void home ();
- X public void add_line ();
- X public void lower_left ();
- X public void bell ();
- X public void vbell ();
- X public void clear ();
- X public void clear_eol ();
- X public void so_enter ();
- X public void so_exit ();
- X public void ul_enter ();
- X public void ul_exit ();
- X public void bo_enter ();
- X public void bo_exit ();
- X public void backspace ();
- X public void putbs ();
- X public char * eq_message ();
- X public char * pr_string ();
- X public void prewind ();
- X public int pappend ();
- X public POSITION forw_raw_line ();
- X public POSITION back_raw_line ();
- X public void init_signals ();
- X public void psignals ();
- X public void lsystem ();
- X public void help ();
- X public void open_getc ();
- X public int getc ();
- X public void commands ();
- SHAR_EOF
- fi
- if test -f 'help.c'
- then
- echo shar: "will not over-write existing file 'help.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'help.c'
- X#include "less.h"
- X
- X/*
- X * Display some help.
- X * Just invoke another "less" to display the help file.
- X *
- X * {{ This makes this function very simple, and makes changing the
- X * help file very easy, but it may present difficulties on
- X * (non-Unix) systems which do not supply the "system()" function. }}
- X */
- X
- X public void
- Xhelp()
- X{
- X char cmd[200];
- X
- X sprintf(cmd,
- X "-less -m '-Pm<HELP -- Press RETURN for more, or q when done >' %s",
- X HELPFILE);
- X lsystem(cmd);
- X error("End of help");
- X}
- SHAR_EOF
- fi
- if test -f 'input.c'
- then
- echo shar: "will not over-write existing file 'input.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'input.c'
- X/*
- X * High level routines dealing with getting lines of input
- X * from the file being viewed.
- X *
- X * When we speak of "lines" here, we mean PRINTABLE lines;
- X * lines processed with respect to the screen width.
- X * We use the term "raw line" to refer to lines simply
- X * delimited by newlines; not processed with respect to screen width.
- X */
- X
- X#include "less.h"
- X
- Xextern int squeeze;
- Xextern char *line;
- X
- X/*
- X * Get the next line.
- X * A "current" position is passed and a "new" position is returned.
- X * The current position is the position of the first character of
- X * a line. The new position is the position of the first character
- X * of the NEXT line. The line obtained is the line starting at curr_pos.
- X */
- X public POSITION
- Xforw_line(curr_pos)
- X POSITION curr_pos;
- X{
- X POSITION new_pos;
- X register int c;
- X
- X if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
- X return (NULL_POSITION);
- X
- X c = ch_forw_get();
- X if (c == EOF)
- X return (NULL_POSITION);
- X
- X prewind();
- X for (;;)
- X {
- X if (c == '\n' || c == EOF)
- X {
- X /*
- X * End of the line.
- X */
- X new_pos = ch_tell();
- X break;
- X }
- X
- X /*
- X * Append the char to the line and get the next char.
- X */
- X if (pappend(c))
- X {
- X /*
- X * The char won't fit in the line; the line
- X * is too long to print in the screen width.
- X * End the line here.
- X */
- X new_pos = ch_tell() - 1;
- X break;
- X }
- X c = ch_forw_get();
- X }
- X (void) pappend('\0');
- X
- X if (squeeze && *line == '\0')
- X {
- X /*
- X * This line is blank.
- X * Skip down to the last contiguous blank line
- X * and pretend it is the one which we are returning.
- X */
- X while ((c = ch_forw_get()) == '\n')
- X ;
- X if (c != EOF)
- X (void) ch_back_get();
- X new_pos = ch_tell();
- X }
- X
- X return (new_pos);
- X}
- X
- X/*
- X * Get the previous line.
- X * A "current" position is passed and a "new" position is returned.
- X * The current position is the position of the first character of
- X * a line. The new position is the position of the first character
- X * of the PREVIOUS line. The line obtained is the one starting at new_pos.
- X */
- X public POSITION
- Xback_line(curr_pos)
- X POSITION curr_pos;
- X{
- X POSITION new_pos, begin_new_pos;
- X int c;
- X
- X if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
- X ch_seek(curr_pos-1))
- X return (NULL_POSITION);
- X
- X if (squeeze)
- X {
- X /*
- X * Find out if the "current" line was blank.
- X */
- X (void) ch_forw_get(); /* Skip the newline */
- X c = ch_forw_get(); /* First char of "current" line */
- X (void) ch_back_get(); /* Restore our position */
- X (void) ch_back_get();
- X
- X if (c == '\n')
- X {
- X /*
- X * The "current" line was blank.
- X * Skip over any preceeding blank lines,
- X * since we skipped them in forw_line().
- X */
- X while ((c = ch_back_get()) == '\n')
- X ;
- X if (c == EOF)
- X return (NULL_POSITION);
- X (void) ch_forw_get();
- X }
- X }
- X
- X /*
- X * Scan backwards until we hit the beginning of the line.
- X */
- X for (;;)
- X {
- X c = ch_back_get();
- X if (c == '\n')
- X {
- X /*
- X * This is the newline ending the previous line.
- X * We have hit the beginning of the line.
- X */
- X new_pos = ch_tell() + 1;
- X break;
- X }
- X if (c == EOF)
- X {
- X /*
- X * We have hit the beginning of the file.
- X * This must be the first line in the file.
- X * This must, of course, be the beginning of the line.
- X */
- X new_pos = ch_tell();
- X break;
- X }
- X }
- X
- X /*
- X * Now scan forwards from the beginning of this line.
- X * We keep discarding "printable lines" (based on screen width)
- X * until we reach the curr_pos.
- X *
- X * {{ This algorithm is pretty inefficient if the lines
- X * are much longer than the screen width,
- X * but I don't know of any better way. }}
- X */
- X if (ch_seek(new_pos))
- X return (NULL_POSITION);
- X loop:
- X begin_new_pos = new_pos;
- X prewind();
- X
- X do
- X {
- X c = ch_forw_get();
- X new_pos++;
- X if (c == '\n')
- X break;
- X if (pappend(c))
- X {
- X /*
- X * Got a full printable line, but we haven't
- X * reached our curr_pos yet. Discard the line
- X * and start a new one.
- X */
- X (void) pappend('\0');
- X (void) ch_back_get();
- X new_pos--;
- X goto loop;
- X }
- X } while (new_pos < curr_pos);
- X
- X (void) pappend('\0');
- X
- X return (begin_new_pos);
- X}
- SHAR_EOF
- fi
- if test -f 'install'
- then
- echo shar: "will not over-write existing file 'install'"
- else
- sed 's/^X//' << \SHAR_EOF > 'install'
- X:
- X# Installation script for less.
- X# This script prompts the operator for various information
- X# and constructs a makefile.
- X
- Xecho "This script will build a makefile for less."
- Xecho "If you already have a file called \"makefile\" it will be overwritten."
- Xecho "Press RETURN to continue."
- Xread ans
- X
- Xecho "I will ask you some questions about your system."
- Xecho "If you do not know the answer to any question,"
- Xecho "just press RETURN and I will choose a default for you."
- Xecho "Press RETURN now."
- Xread ans
- X
- Xecho "Most Unix systems are derived from either System V"
- Xecho "or Berkeley BSD 4.1, 4.2, 4.3, etc."
- Xecho ""
- Xecho "Is your system closest to:"
- Xecho " 1. System V"
- Xecho " 2. BSD 2.11 or later"
- Xecho " 3. BSD 4.1"
- Xecho " 4. BSD 4.2 or later"
- Xecho " 5. Xenix"
- Xecho "Enter a number, or just RETURN if you don't know: \c"
- Xread ans
- Xxenix=0
- Xcase "X$ans" in
- XX1) sys=sys5; sysname="System V" ;;
- XX2) sys=bsd; bsd41=0; bsd2=1; sysname="BSD 2.11" ;;
- XX3) sys=bsd; bsd41=1; bsd2=0; sysname="BSD 4.1" ;;
- XX4) sys=bsd; bsd41=0; bsd2=0; sysname="BSD 4.2" ;;
- XX5) sys=sys5; xenix=1; sysname="Xenix" ;;
- X*) sys=unknown ;;
- Xesac
- Xecho ""
- X
- Xcat >makefile <<"EOF"
- X# Makefile for "less"
- X#
- X# Invoked as:
- X# make all
- X# or make install
- X# Plain "make" is equivalent to "make all".
- X#
- X# If you add or delete functions, remake funcs.h by doing:
- X# make newfuncs
- X# This depends on the coding convention of function headers looking like:
- X# " \t public <function-type> \n <function-name> ( ... ) "
- X#
- X# Also provided:
- X# make lint # Runs "lint" on all the sources.
- X# make clean # Removes "less" and the .o files.
- X# make clobber # Pretty much the same as make "clean".
- X
- X
- X##########################################################################
- X# System-specific parameters
- X##########################################################################
- X
- XEOF
- X
- Xcat >>makefile <<EOF
- X# Define XENIX if running under XENIX 3.0
- XXENIX = $xenix
- X
- XEOF
- Xecho ""
- X
- X
- X
- Xif [ "X$sys" = "Xunknown" ]
- Xthen
- X alldefault=0
- Xelse
- X def=yes
- X alldefault=1
- X echo "Do you want to use ALL the defaults for $sysname?"
- X echo " Enter \"yes\" if you have a STANDARD $sysname."
- X echo " Enter \"no\" if you want to change any of the defaults. [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) alldefault=1 ;;
- X X[nN]*) alldefault=0 ;;
- X esac
- X echo ""
- Xfi
- X
- X
- X
- Xdef=yes
- Xx=1
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Does your C compiler support the \"void\" type? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) x=1 ;;
- X X[nN]*) x=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# VOID is 1 if your C compiler supports the "void" type,
- X# 0 if it does not.
- XVOID = $x
- X
- XEOF
- X
- X
- X
- Xdef=long
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "What type is the \"offset\" argument to lseek? [$def] \c"
- X read ans
- X if [ "X$ans" != "X" ]
- X then
- X def=$ans
- X fi
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# off_t is the type which lseek() returns.
- X# It is also the type of lseek()'s second argument.
- Xoff_t = $def
- X
- XEOF
- X
- X
- X
- X
- Xif [ "$sys" = "bsd" ]
- Xthen
- X def=no; x=0
- Xelse
- X def=yes; x=1
- Xfi
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Most System V systems have termio.h, while most"
- X echo "Berkeley-derived systems have sgtty.h."
- X echo "Does your system have termio.h? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) x=1 ;;
- X X[nN]*) x=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# TERMIO is 1 if your system has /usr/include/termio.h.
- X# This is normally the case for System 5.
- X# If TERMIO is 0 your system must have /usr/include/sgtty.h.
- X# This is normally the case for BSD.
- XTERMIO = $x
- X
- XEOF
- X
- X
- X
- X
- Xif [ "$sys" = "bsd" -a "$bsd41" = "0" ]
- Xthen
- X def=yes; x=1
- Xelse
- X def=no; x=0
- Xfi
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Most BSD 4.2 and 4.3 systems have the sigsetmask() call."
- X echo "Most System V and BSD 4.1 systems do not."
- X echo "Does your system have sigsetmask()? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) x=1 ;;
- X X[nN]*) x=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# SIGSETMASK is 1 if your system has the sigsetmask() call.
- X# This is normally the case only for BSD 4.2,
- X# not for BSD 4.1 or System 5.
- XSIGSETMASK = $x
- X
- XEOF
- X
- Xcat >>makefile <<EOF
- X##########################################################################
- X# Optional and semi-optional features
- X##########################################################################
- X
- XEOF
- X
- X
- X
- X
- Xif [ "$sys" = "bsd" ]
- Xthen
- X def=2; REGCMP=0;RECOMP=1
- Xelse
- X def=1; REGCMP=1;RECOMP=0
- Xfi
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Most System V systems have the regcmp() function."
- X echo "Most Berkeley-derived systems have the re_comp() function."
- X echo "Does your system have:"
- X echo " 1. regcmp"
- X echo " 2. re_comp"
- X echo " 3. neither [$def] \c"
- X read ans
- X case "X$ans" in
- X X1) REGCMP=1;RECOMP=0 ;;
- X X2) REGCMP=0;RECOMP=1 ;;
- X X3) REGCMP=0;RECOMP=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# REGCMP is 1 if your system has the regcmp() function.
- X# This is normally the case for System 5.
- X# RECOMP is 1 if your system has the re_comp() function.
- X# This is normally the case for BSD.
- X# If neither is 1, pattern matching is supported, but without metacharacters.
- XREGCMP = $REGCMP
- XRECOMP = $RECOMP
- X
- XEOF
- X
- X
- X
- X
- Xdef=yes
- Xx=1
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Do you wish to allow shell escapes? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) x=1 ;;
- X X[nN]*) x=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# SHELL_ESCAPE is 1 if you wish to allow shell escapes.
- X# (This is possible only if your system supplies the system() function.)
- XSHELL_ESCAPE = $x
- X
- XEOF
- X
- X
- X
- Xdef=yes
- Xx=1
- Xedname="vi"
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Do you wish to allow editor escapes? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[nN]*) x=0; edname="" ;;
- X X[yY]*) x=1
- X echo "What is the pathname of the default editor? [$edname] \c"
- X read ans
- X if [ "x$ans" != "x" ]
- X then
- X edname=$ans
- X fi
- X ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# EDITOR is 1 if you wish to allow editor invocation (the "v" command).
- X# (This is possible only if your system supplies the system() function.)
- X# EDIT_PGM is the name of the (default) editor to be invoked.
- XEDITOR = $x
- XEDIT_PGM = $edname
- X
- XEOF
- X
- X
- X
- Xdef=yes
- Xx=1
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "If your system provides the popen() function and"
- X echo "the \"echo\" shell command, you may allow shell metacharacters"
- X echo "to be expanded in filenames."
- X echo "Do you wish to allow shell metacharacters in filenames? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) x=1 ;;
- X X[nN]*) x=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# GLOB is 1 if you wish to have shell metacharacters expanded in filenames.
- X# This will generally work if your system provides the "popen" function
- X# and the "echo" shell command.
- XGLOB = $x
- X
- XEOF
- X
- X
- X
- Xdef=yes
- Xx=1
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "Do you wish to allow log files (-l option)? [$def] \c"
- X read ans
- X case "X$ans" in
- X X[yY]*) x=1 ;;
- X X[nN]*) x=0 ;;
- X esac
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# LOGFILE is 1 if you wish to allow the -l option (to create log files).
- XLOGFILE = $x
- X
- XEOF
- X
- Xcat >>makefile <<EOF
- X# ONLY_RETURN is 1 if you want RETURN to be the only input which
- X# will continue past an error message.
- X# Otherwise, any key will continue past an error message.
- XONLY_RETURN = 0
- X
- X
- X##########################################################################
- X# Compilation environment.
- X##########################################################################
- X
- XEOF
- X
- X
- X
- Xif [ "$xenix" = "1" ]
- Xthen
- X LIBS="-ltermlib"
- Xelif [ "$sys" = "bsd" ]
- Xthen
- X LIBS="-ltermcap"
- Xelse
- X LIBS="-lcurses -ltermcap -lPW"
- Xfi
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "To build \"less\", you must link with libraries supplied by your system."
- X echo "(If this needs to be changed later, edit the makefile"
- X echo "and change the definition of LIBS.)"
- X echo "What libraries should be used [$LIBS] \c"
- X read ans
- X if [ "X$ans" != "X" ]
- X then
- X LIBS="$ans"
- X fi
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# LIBS is the list of libraries needed.
- XLIBS = $LIBS
- X
- XEOF
- X
- X
- Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
- Xthen
- X INSTALL_LESS="/usr/local/less"
- X INSTALL_HELP="/usr/local/lib/less.help"
- X INSTALL_MAN="/usr/local/man/cat1/less.0"
- X MANUAL="less.nro"
- Xelse
- X INSTALL_LESS="/usr/local/bin/less"
- X INSTALL_HELP="/usr/local/bin/less.help"
- X INSTALL_MAN="/usr/man/man1/less.1"
- X MANUAL="less.nro"
- Xfi
- X
- Xif [ $alldefault = 0 ]
- Xthen
- X echo "What is the name of the \"public\" (installed) version of less?"
- X echo " [$INSTALL_LESS] \c"
- X read ans
- X if [ "X$ans" != "X" ]
- X then
- X INSTALL_LESS="$ans"
- X fi
- X echo "What is the name of the \"public\" (installed) version of the help file?"
- X echo " [$INSTALL_HELP] \c"
- X read ans
- X if [ "X$ans" != "X" ]
- X then
- X INSTALL_HELP="$ans"
- X fi
- X echo "What is the name of the \"public\" (installed) version of the manual page?"
- X echo " [$INSTALL_MAN] \c"
- X read ans
- X if [ "X$ans" != "X" ]
- X then
- X INSTALL_MAN="$ans"
- X fi
- X echo ""
- Xfi
- Xcat >>makefile <<EOF
- X# INSTALL_LESS is a list of the public versions of less.
- X# INSTALL_HELP is a list of the public version of the help file.
- X# INSTALL_MAN is a list of the public versions of the manual page.
- XINSTALL_LESS = $INSTALL_LESS
- XINSTALL_HELP = $INSTALL_HELP
- XINSTALL_MAN = $INSTALL_MAN
- XMANUAL = $MANUAL
- XHELPFILE = $INSTALL_HELP
- X
- X
- XEOF
- X
- X
- X
- Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
- Xthen
- Xcat >>makefile <<"EOF"
- X# OPTIM is passed to the compiler and the loader.
- X# It is normally "-O" but may be, for example, "-g".
- XOPTIM = -O -i
- XEOF
- X
- Xelse
- Xcat >>makefile <<"EOF"
- X# OPTIM is passed to the compiler and the loader.
- X# It is normally "-O" but may be, for example, "-g".
- XOPTIM = -O
- XEOF
- X
- Xfi
- X
- X
- Xcat >>makefile <<"EOF"
- X
- X
- X##########################################################################
- X# Files
- X##########################################################################
- X
- XSRC1 = main.c option.c prim.c ch.c position.c input.c output.c
- XSRC2 = screen.c prompt.c line.c signal.c help.c ttyin.c command.c version.c
- XSRC = $(SRC1) $(SRC2)
- XOBJ = main.o option.o prim.o ch.o position.o input.o output.o screen.o \
- X prompt.o line.o signal.o help.o ttyin.o command.o version.o
- X
- X
- X##########################################################################
- X# Rules
- X##########################################################################
- X
- XDEFS = "-DTERMIO=$(TERMIO)" \
- X "-DSIGSETMASK=$(SIGSETMASK)" \
- X "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
- X "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
- X "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
- X "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
- X "-DHELPFILE=\"$(HELPFILE)\"" \
- X "-DLOGFILE=$(LOGFILE)" \
- X "-DONLY_RETURN=$(ONLY_RETURN)" \
- X "-DGLOB=$(GLOB)" \
- X "-DXENIX=$(XENIX)"
- X
- XCFLAGS = $(OPTIM) $(DEFS)
- X
- X
- Xall: less
- X
- Xless: $(OBJ)
- X cc $(OPTIM) -o less $(OBJ) $(LIBS)
- X
- Xinstall: install_man install_less install_help
- X
- Xinstall_less: less
- X for f in $(INSTALL_LESS); do rm -f $$f; cp less $$f; done
- X touch install_less
- X
- Xinstall_help: less.help
- X for f in $(INSTALL_HELP); do rm -f $$f; cp less.help $$f; done
- X touch install_help
- X
- XEOF
- X
- Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
- Xthen
- Xcat >>makefile <<"EOF"
- Xinstall_man: $(MANUAL)
- X rm -f $(INSTALL_MAN)
- X /usr/man/manroff $(MANUAL) > $(INSTALL_MAN)
- X chmod 444 $(INSTALL_MAN)
- X chown bin.bin $(INSTALL_MAN)
- X touch install_man
- X
- XEOF
- X
- Xelse
- Xcat >>makefile <<"EOF"
- Xinstall_man: $(MANUAL)
- X for f in $(INSTALL_MAN); do rm -f $$f; cp $(MANUAL) $$f; done
- X touch install_man
- X
- XEOF
- Xfi
- X
- Xcat >>makefile <<"EOF"
- X$(OBJ): less.h funcs.h
- X
- X# help.o depends on makefile for the definition of HELPFILE.
- Xhelp.o: makefile
- X
- Xlint:
- X lint -hp $(DEFS) $(SRC)
- X
- Xnewfuncs:
- X mv funcs.h funcs.h.OLD
- X awk -f mkfuncs.awk $(SRC) >funcs.h
- X
- XEOF
- X
- X
- Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
- Xthen
- Xcat >>makefile <<"EOF"
- Xclean:
- X rm -f $(OBJ) less install_help install_less install_man core
- X
- XEOF
- X
- Xelse
- Xcat >>makefile <<"EOF"
- Xclean:
- X rm -f $(OBJ) less
- X
- XEOF
- Xfi
- X
- Xcat >>makefile <<"EOF"
- Xclobber:
- X rm -f *.o less install_less install_man
- X
- Xshar:
- X shar -v README install less.help makefile.* *.h *.awk > less.shar.a
- X shar -v less.nro $(SRC1) > less.shar.b
- X shar -v $(SRC2) > less.shar.c
- XEOF
- Xecho ""
- X
- Xecho "The makefile has been built."
- Xecho "You should check it to make sure everything is as you want it to be."
- Xecho "When you are satisfied with the makefile, just type \"make\""
- Xecho "and \"less\" will be built."
- SHAR_EOF
- chmod +x 'install'
- fi
- if test -f 'less.h'
- then
- echo shar: "will not over-write existing file 'less.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'less.h'
- X/*
- X * Standard include file for "less".
- X */
- X
- X/*
- X * Language details.
- X */
- X#if !VOID
- X#define void int
- X#endif
- X#define public /* PUBLIC FUNCTION */
- X
- X/*
- X * Special types and constants.
- X */
- Xtypedef long POSITION;
- X/*
- X * {{ Warning: if POSITION is changed to other than "long",
- X * you may have to change some of the printfs which use "%ld"
- X * to print a variable of type POSITION. }}
- X */
- X
- X#define NULL_POSITION ((POSITION)(-1))
- X
- X#define EOF (0)
- X#define NULL (0)
- X
- X/* How quiet should we be? */
- X#define NOT_QUIET 0 /* Ring bell at eof and for errors */
- X#define LITTLE_QUIET 1 /* Ring bell only for errors */
- X#define VERY_QUIET 2 /* Never ring bell */
- X
- X/* How should we prompt? */
- X#define PR_SHORT 0 /* Prompt with colon */
- X#define PR_MEDIUM 1 /* Prompt with message */
- X#define PR_LONG 2 /* Prompt with longer message */
- X
- X/* How should we handle backspaces? */
- X#define BS_SPECIAL 0 /* Do special things for underlining and bold */
- X#define BS_NORMAL 1 /* \b treated as normal char; actually output */
- X#define BS_CONTROL 2 /* \b treated as control char; prints as ^H */
- X
- X/* Special chars used to tell put_line() to do something special */
- X#define UL_CHAR '\201' /* Enter underline mode */
- X#define UE_CHAR '\202' /* Exit underline mode */
- X#define BO_CHAR '\203' /* Enter boldface mode */
- X#define BE_CHAR '\204' /* Exit boldface mode */
- X
- X#define CONTROL(c) ((c)&037)
- X#define SIGNAL(sig,func) signal(sig,func)
- X
- X/* Library function declarations */
- Xoff_t lseek();
- X
- X#include "funcs.h"
- SHAR_EOF
- fi
- if test -f 'less.help'
- then
- echo shar: "will not over-write existing file 'less.help'"
- else
- sed 's/^X//' << \SHAR_EOF > 'less.help'
- X
- X Commands marked with * may be preceeded by a number, N.
- X
- X h Display this help.
- X q Exit.
- X
- X f, SPACE * Forward N lines, default one screen.
- X b * Backward N lines, default one screen.
- X e, j, CR * Forward N lines, default 1 line.
- X y, k * Backward N lines, default 1 line.
- X d * Forward N lines, default 10 or last N to d or u command.
- X u * Backward N lines, default 10 or last N to d or u command.
- X r Repaint screen.
- X R Repaint screen, discarding buffered input.
- X
- X /pattern * Search forward for N-th line containing the pattern.
- X ?pattern * Search backward for N-th line containing the pattern.
- X n * Repeat previous search (for N-th occurence).
- X
- X g * Go to line N, default 1.
- X G * Like g, but default is last line in file.
- X p, % * Position to N percent into the file.
- X m<letter> Mark the current position with <letter>.
- X '<letter> Return to a previously marked position.
- X '' Return to previous position.
- X
- X E [file] Examine a new file.
- X N * Examine the next file (from the command line).
- X P * Examine the previous file (from the command line).
- X = Print current file name.
- X V Print version number of "less".
- X
- X -<flag> Toggle a command line flag.
- X +cmd Execute the less cmd each time a new file is examined.
- X
- X !command Passes the command to a shell to be executed.
- X v Edit the current file with $EDITOR.
- SHAR_EOF
- fi
- if test -f 'less.nro'
- then
- echo shar: "will not over-write existing file 'less.nro'"
- else
- sed 's/^X//' << \SHAR_EOF > 'less.nro'
- X.TH LESS LOCAL
- X.SH NAME
- Xless \- opposite of more
- X.SH SYNOPSIS
- X.B "less [-cdepstwmMqQuU] [-h\fIN\fB] [-b[fp]\fIN\fB] [-x\fIN\fB] [-[z]\fIN\fB]"
- X.br
- X.B " [-P[mM]\fIstring\fB] [-l\fIlogfile\fB] [+\fIcmd\fB] [\fIfilename\fB]..."
- X.SH DESCRIPTION
- X.I Less
- Xis a program similar to
- X.I more
- X(1), but which allows backwards movement
- Xin the file as well as forward movement.
- XAlso,
- X.I less
- Xdoes not have to read the entire input file before starting,
- Xso with large input files it starts up faster than text editors like
- X.I vi
- X(1).
- X.I Less
- Xuses termcap, so it can run on a variety of terminals.
- XThere is even limited support for hardcopy terminals.
- X(On a hardcopy terminal, lines which should be printed at the top
- Xof the screen are prefixed with an up-arrow.)
- X.PP
- XCommands are based on both
- X.I more
- Xand
- X.I vi.
- XCommands may be preceeded by a decimal number,
- Xcalled N in the descriptions below.
- XThe number is used by some commands, as indicated.
- X
- X.SH COMMANDS
- XIn the following descriptions, ^X means control-X.
- X.IP h
- XHelp: display a summary of these commands.
- XIf you forget all the other commands, remember this one.
- X.PP
- X.IP SPACE
- XScroll forward N lines, default one window (see option \-z below).
- XIf N is more than the screen size, only the final screenful is displayed.
- X.PP
- X.IP "f or ^F"
- XSame as SPACE.
- X.PP
- X.IP "b or ^B"
- XScroll backward N lines, default one window (see option \-z below).
- XIf N is more than the screen size, only the final screenful is displayed.
- X.PP
- X.IP RETURN
- XScroll forward N lines, default 1.
- XThe entire N lines are displayed, even if N is more than the screen size.
- X.PP
- X.IP "e or ^E"
- XSame as RETURN.
- X.PP
- X.IP "j or ^J"
- XAlso the same as RETURN.
- X.PP
- X.IP "y or ^Y"
- XScroll backward N lines, default 1.
- XThe entire N lines are displayed, even if N is more than the screen size.
- X.IP "k or ^K"
- XSame as y.
- X.PP
- X.IP "d or ^D"
- XScroll forward N lines, default 10.
- XIf N is specified, it becomes the new default for
- Xsubsequent d and u commands.
- X.PP
- X.IP "u or ^U"
- XScroll backward N lines, default 10.
- XIf N is specified, it becomes the new default for
- Xsubsequent d and u commands.
- X.PP
- X.IP "r or ^R or ^L"
- XRepaint the screen.
- X.PP
- X.IP R
- XRepaint the screen, discarding any buffered input.
- XUseful if the file is changing while it is being viewed.
- X.PP
- X.IP g
- XGo to line N in the file, default 1 (beginning of file).
- X(Warning: this may be slow if N is large.)
- X.PP
- X.IP G
- XGo to line N in the file, default the end of the file.
- X(Warning: this may be slow if standard input,
- Xrather than a file, is being read.)
- X.PP
- X.IP p
- XGo to a position N percent into the file.
- XN should be between 0 and 100.
- X(This is possible if standard input is being read,
- Xbut only if
- X.I less
- Xhas already read to the end of the file.
- XIt is always fast, but not always useful.)
- X.PP
- X.IP %
- XSame as p.
- X.PP
- X.IP m
- XFollowed by any lowercase letter,
- Xmarks the current position with that letter.
- X.PP
- X.IP "'"
- X(Single quote.)
- XFollowed by any lowercase letter, returns to the position which
- Xwas previously marked with that letter.
- XFollowed by another single quote, returns to the postion at
- Xwhich the last "large" movement command was executed.
- XAll marks are lost when a new file is examined.
- X.PP
- X.IP /pattern
- XSearch forward in the file for the N-th line containing the pattern.
- XN defaults to 1.
- XThe pattern is a regular expression, as recognized by
- X.I ed.
- XThe search starts at the second line displayed
- X(but see the \-t option, which changes this).
- X.PP
- X.IP ?pattern
- XSearch backward in the file for the N-th line containing the pattern.
- XThe search starts at the line immediately before the top line displayed.
- X.PP
- X.IP n
- XRepeat previous search, for N-th line containing the last pattern.
- X.PP
- X.IP E [filename]
- XExamine a new file.
- XIf the filename is missing, the "current" file (see the N and P commands
- Xbelow) from the list of files in the command line is re-examined.
- X.PP
- X.IP N
- XExamine the next file (from the list of files given in the command line).
- XIf a number N is specified (not to be confused with the command N),
- Xthe N-th next file is examined.
- X.PP
- X.IP P
- XExamine the previous file.
- XIf a number N is specified, the N-th previous file is examined.
- X.PP
- X.IP "= or ^G"
- XPrints some information about the file being viewed,
- Xincluding its name
- Xand the byte offset of the bottom line being displayed.
- XIf possible, it also prints the length of the file
- Xand the percent of the file above the last displayed line.
- X.PP
- X.IP \-
- XFollowed by one of the command line option letters (see below),
- Xthis will toggle the setting of that option
- Xand print a message describing the new setting.
- X.PP
- X.IP +cmd
- XCauses the specified cmd to be executed each time a new file is examined.
- XFor example, +G causes
- X.I less
- Xto initially display each file starting at the end
- Xrather than the beginning.
- X.PP
- X.IP V
- XPrints the version number of
- X.I less
- Xbeing run.
- X.PP
- X.IP q
- XExits
- X.I less.
- X.PP
- XThe following
- Xtwo
- Xcommands may or may not be valid, depending on your particular installation.
- X.PP
- X.IP v
- XInvokes an editor to edit the current file being viewed.
- XThe editor is taken from the environment variable EDITOR,
- Xor defaults to "vi".
- X.PP
- X.IP "! shell-command"
- XInvokes a shell to run the shell-command given.
- X.PP
- X.SH OPTIONS
- XCommand line options are described below.
- XMost options may be changed while
- X.I less
- Xis running, via the "\-" command.
- X.PP
- XOptions are also taken from the environment variable "LESS".
- XFor example, if you like
- Xmore-style prompting, to avoid typing "less \-m ..." each time
- X.I less
- Xis invoked, you might tell
- X.I csh:
- X.sp
- Xsetenv LESS m
- X.sp
- Xor if you use
- X.I sh:
- X.sp
- XLESS=m; export LESS
- X.sp
- XThe environment variable is parsed before the command line,
- Xso command line options override the LESS environment variable.
- XA dollar sign ($) may be used to signal the end of an option string.
- XThis is important only for options like \-P which take a
- Xfollowing string.
- X.IP \-s
- XThe \-s option causes
- Xconsecutive blank lines to be squeezed into a single blank line.
- XThis is useful when viewing
- X.I nroff
- Xoutput.
- X.IP \-t
- XNormally, forward searches start just after
- Xthe top displayed line (that is, at the second displayed line).
- XThus forward searches include the currently displayed screen.
- XThe \-t option causes forward searches to start
- Xjust after the bottom line displayed,
- Xthus skipping the currently displayed screen.
- X.IP \-m
- XNormally,
- X.I less
- Xprompts with a colon.
- XThe \-m option causes
- X.I less
- Xto prompt verbosely (like
- X.I more),
- Xwith the percent into the file.
- X.IP \-M
- XThe \-M option causes
- X.I less
- Xto prompt even more verbosely than
- X.I more.
- X.IP \-P
- XThe \-P option provides a way to tailor the three prompt
- Xstyles to your own preference.
- XYou would normally put this option in your LESS environment
- Xvariable, rather than type it in with each less command.
- XSuch an option must either be the last option in the LESS variable,
- Xor be terminated by a dollar sign.
- X\-P followed by a string changes the default (short) prompt to that string.
- X\-Pm changes the medium (\-m) prompt to the string, and
- X\-PM changes the long (\-M) prompt.
- XThe string consists of a sequence of letters which are replaced
- Xwith certain predefined strings, as follows:
- X.br
- X F file name
- X.br
- X f file name, only once
- X.br
- X O file n of n
- X.br
- X o file n of n, only once
- X.br
- X b byte offset
- X.br
- X p percent into file
- X.br
- X P percent if known, else byte offset
- X.br
- XAngle brackets, < and >, may be used to surround a
- Xliteral string to be included in the prompt.
- XThe defaults are "fo" for the short prompt,
- X"foP" for the medium prompt, and
- X"Fobp" for the long prompt.
- X.br
- XExample: Setting your LESS variable to "PmFOP$PMFObp"
- Xwould change the medium and long prompts to always
- Xinclude the file name and "file n of n" message.
- X.br
- XAnother example: Setting your LESS variable to
- X.br
- X"mPm<--Less-->FoPe"
- Xwould change the medium prompt to the string "--Less--" followed
- Xby the file name and percent into the file.
- XIt also selects the medium
- Xprompt as the default prompt (because of the first "m").
- X.IP \-q
- XNormally, if an attempt is made to scroll past the end of the file
- Xor before the beginning of the file, the terminal bell is rung to
- Xindicate this fact.
- XThe \-q option tells
- X.I less
- Xnot to ring the bell at such times.
- XIf the terminal has a "visual bell", it is used instead.
- X.IP \-Q
- XEven if \-q is given,
- X.I less
- Xwill ring the bell on certain other errors,
- Xsuch as typing an invalid character.
- XThe \-Q option tells
- X.I less
- Xto be quiet all the time; that is, never ring the terminal bell.
- XIf the terminal has a "visual bell", it is used instead.
- X.IP \-e
- XNormally the only way to exit less is via the "q" command.
- XThe \-e option tells less to automatically exit
- Xthe second time it reaches end-of-file.
- X.IP \-u
- XIf the \-u option is given,
- Xbackspaces are treated as printable characters;
- Xthat is, they are sent to the terminal when they appear in the input.
- X.IP \-U
- XIf the \-U option is given,
- Xbackspaces are printed as the two character sequence "^H".
- X.sp
- XIf neither \-u nor \-U is given,
- Xbackspaces which appear adjacent to an underscore character
- Xare treated specially:
- Xthe underlined text is displayed
- Xusing the terminal's hardware underlining capability.
- XAlso, backspaces which appear between two identical characters
- Xare treated specially:
- Xthe overstruck text is printed
- Xusing the terminal's hardware boldface capability.
- XOther backspaces are deleted, along with the preceeding character.
- X.IP \-w
- XNormally,
- X.I less
- Xuses a tilde character to represent lines past the end of the file.
- XThe \-w option causes blank lines to be used instead.
- X.IP \-d
- XNormally,
- X.I less
- Xwill complain if the terminal is dumb; that is, lacks some important capability,
- Xsuch as the ability to clear the screen or scroll backwards.
- XThe \-d option suppresses this complaint
- X(but does not otherwise change the behavior of the program on a dumb terminal).
- X.IP \-p
- XNormally,
- X.I less
- Xwill repaint the screen by scrolling from the bottom of the screen.
- XIf the \-p option is set, when
- X.I less
- Xneeds to change the entire display, it will clear the screen
- Xand paint from the top line down.
- X.IP \-h
- XNormally,
- X.I less
- Xwill scroll backwards when backwards movement is necessary.
- XThe \-h option specifies a maximum number of lines to scroll backwards.
- XIf it is necessary to move backwards more than this many lines,
- Xthe screen is repainted in a forward direction.
- X(If the terminal does not have the ability to scroll
- Xbackwards, \-h0 is implied.)
- X.IP \-[z]
- XWhen given a backwards or forwards window command,
- X.I less
- Xwill by
- Xdefault scroll backwards or forwards one screenful of lines.
- XThe \-z\fIn\fR option changes the default scrolling window size
- Xto \fIn\fR lines.
- XIf \fIn\fR is greater than the screen size,
- Xthe scrolling window size will be set to one screenful.
- XNote that the "z" is optional for compatibility with
- X.I more.
- X.IP -x
- XThe -x\fIn\fR option sets tab stops every \fIn\fR positions.
- XThe default for \fIn\fR is 8.
- X.IP -l
- XThe -l option, followed immediately by a filename,
- Xwill cause
- X.I less
- Xto copy its input to the named file as it is being viewed.
- XThis applies only when the input file is a pipe,
- Xnot an ordinary file.
- X.IP -b
- XThe -b\fIn\fR option tells
- X.I less
- Xto use a non-standard buffer size.
- XThere are two standard (default) buffer sizes,
- Xone is used when a file is being read and the other
- Xwhen a pipe (standard input) is being read.
- XThe current defaults are 5 buffers for files and 12 for pipes.
- X(Buffers are 1024 bytes.)
- XThe number \fIn\fR specifies a different number of buffers to use.
- XThe -b may be followed by "f", in which case only
- Xthe file default is changed, or by "p" in which case only the
- Xpipe default is changed. Otherwise, both are changed.
- X.IP -c
- XNormally, when data is read by
- X.I less,
- Xit is scanned to ensure that bit 7 (the high order bit) is turned off in
- Xeach byte read, and to ensure that there are no null (zero) bytes in
- Xthe data (null bytes are turned into "@" characters).
- XIf the data is known to be "clean",
- Xthe -c option will tell
- X.I less
- Xto skip this checking, causing an imperceptible speed improvement.
- X(However, if the data is not "clean", unpredicatable results may occur.)
- X.IP +
- XIf a command line option begins with \fB+\fR,
- Xthe remainder of that option is taken to be an initial command to
- X.I less.
- XFor example, +G tells
- X.I less
- Xto start at the end of the file rather than the beginning,
- Xand +/xyz tells it to start at the first occurence of "xyz" in the file.
- XAs a special case, +<number> acts like +<number>g;
- Xthat is, it starts the display at the specified line number
- X(however, see the caveat under the "g" command above).
- XIf the option starts with \fB++\fR, the initial command applies to
- Xevery file being viewed, not just the first one.
- XThe + command described previously
- Xmay also be used to set (or change) an initial command for every file.
- X
- X.SH BUGS
- XWhen used on standard input (rather than a file), you can move
- Xbackwards only a finite amount, corresponding to that portion
- Xof the file which is still buffered.
- XThe -b option may be used to expand the buffer space.
- SHAR_EOF
- fi
- if test -f 'line.c'
- then
- echo shar: "will not over-write existing file 'line.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'line.c'
- X/*
- X * Routines to manipulate the "line buffer".
- X * The line buffer holds a line of output as it is being built
- X * in preparation for output to the screen.
- X * We keep track of the PRINTABLE length of the line as it is being built.
- X */
- X
- X#include "less.h"
- X
- Xstatic char linebuf[1024]; /* Buffer which holds the current output line */
- Xstatic char *curr; /* Pointer into linebuf */
- Xstatic int column; /* Printable length, accounting for
- X backspaces, etc. */
- X/*
- X * A ridiculously complex state machine takes care of backspaces
- X * when in BS_SPECIAL mode. The complexity arises from the attempt
- X * to deal with all cases, especially involving long lines with underlining,
- X * boldfacing or whatever. There are still some cases which will break it.
- X *
- X * There are four states:
- X * LN_NORMAL is the normal state (not in underline mode).
- X * LN_UNDERLINE means we are in underline mode. We expect to get
- X * either a sequence like "_\bX" or "X\b_" to continue
- X * underline mode, or anything else to end underline mode.
- X * LN_BOLDFACE means we are in boldface mode. We expect to get sequences
- X * like "X\bX\b...X\bX" to continue boldface mode, or anything
- X * else to end boldface mode.
- X * LN_UL_X means we are one character after LN_UNDERLINE
- X * (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
- X * LN_UL_XB means we are one character after LN_UL_X
- X * (we have gotten the backspace in "_\bX" or "X\b_";
- X * we expect one more ordinary character,
- X * which will put us back in state LN_UNDERLINE).
- X * LN_BO_X means we are one character after LN_BOLDFACE
- X * (we have gotten the 'X' in "X\bX").
- X * LN_BO_XB means we are one character after LN_BO_X
- X * (we have gotten the backspace in "X\bX";
- X * we expect one more 'X' which will put us back
- X * in LN_BOLDFACE).
- X */
- Xstatic int ln_state; /* Currently in normal/underline/bold/etc mode? */
- X#define LN_NORMAL 0 /* Not in underline, boldface or whatever mode */
- X#define LN_UNDERLINE 1 /* In underline, need next char */
- X#define LN_UL_X 2 /* In underline, got char, need \b */
- X#define LN_UL_XB 3 /* In underline, got char & \b, need one more */
- X#define LN_BOLDFACE 4 /* In boldface, need next char */
- X#define LN_BO_X 5 /* In boldface, got char, need \b */
- X#define LN_BO_XB 6 /* In boldface, got char & \b, need same char */
- X
- Xpublic char *line; /* Pointer to the current line.
- X Usually points to linebuf. */
- X
- Xextern int bs_mode;
- Xextern int tabstop;
- Xextern int bo_width, be_width;
- Xextern int ul_width, ue_width;
- Xextern int sc_width, sc_height;
- X
- X/*
- X * Rewind the line buffer.
- X */
- X public void
- Xprewind()
- X{
- X line = curr = linebuf;
- X ln_state = LN_NORMAL;
- X column = 0;
- X}
- X
- X/*
- X * Append a character to the line buffer.
- X * Expand tabs into spaces, handle underlining, boldfacing, etc.
- X * Returns 0 if ok, 1 if couldn't fit in buffer.
- X */
- X
- X#define NEW_COLUMN(newcol) if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \
- X return (1); else column = (newcol)
- X
- X public int
- Xpappend(c)
- X int c;
- X{
- X if (c == '\0')
- X {
- X /*
- X * Terminate any special modes, if necessary.
- X * Append a '\0' to the end of the line.
- X */
- X switch (ln_state)
- X {
- X case LN_UL_X:
- X curr[0] = curr[-1];
- X curr[-1] = UE_CHAR;
- X curr++;
- X break;
- X case LN_BO_X:
- X curr[0] = curr[-1];
- X curr[-1] = BE_CHAR;
- X curr++;
- X break;
- X case LN_UL_XB:
- X case LN_UNDERLINE:
- X *curr++ = UE_CHAR;
- X break;
- X case LN_BO_XB:
- X case LN_BOLDFACE:
- X *curr++ = BE_CHAR;
- X break;
- X }
- X ln_state = LN_NORMAL;
- X *curr = '\0';
- X return (0);
- X }
- X
- X if (curr > linebuf + sizeof(linebuf) - 12)
- X /*
- X * Almost out of room in the line buffer.
- X * Don't take any chances.
- X * {{ Linebuf is supposed to be big enough that this
- X * will never happen, but may need to be made
- X * bigger for wide screens or lots of backspaces. }}
- X */
- X return (1);
- X
- X if (bs_mode == BS_SPECIAL)
- X {
- X /*
- X * Advance the state machine.
- X */
- X switch (ln_state)
- X {
- X case LN_NORMAL:
- X if (curr <= linebuf + 1 || curr[-1] != '\b')
- X break;
- X
- X if (c == curr[-2])
- X goto enter_boldface;
- X if (c == '_' || curr[-2] == '_')
- X goto enter_underline;
- X curr -= 2;
- X break;
- X
- Xenter_boldface:
- X /*
- X * We have "X\bX" (including the current char).
- X * Switch into boldface mode.
- X */
- X if (column + bo_width + be_width + 1 >= sc_width)
- X /*
- X * Not enough room left on the screen to
- X * enter and exit boldface mode.
- X */
- X return (1);
- X
- X if (bo_width > 0 &&
- X curr > linebuf + 2 && curr[-3] == ' ')
- X {
- X /*
- X * Special case for magic cookie terminals:
- X * if the previous char was a space, replace
- X * it with the "enter boldface" sequence.
- X */
- X curr[-3] = BO_CHAR;
- X column += bo_width-1;
- X } else
- X {
- X curr[-1] = curr[-2];
- X curr[-2] = BO_CHAR;
- X column += bo_width;
- X curr++;
- X }
- X goto ln_bo_xb_case;
- X
- Xenter_underline:
- X /*
- X * We have either "_\bX" or "X\b_" (including
- X * the current char). Switch into underline mode.
- X */
- X if (column + ul_width + ue_width + 1 >= sc_width)
- X /*
- X * Not enough room left on the screen to
- X * enter and exit underline mode.
- X */
- X return (1);
- X
- X if (ul_width > 0 &&
- X curr > linebuf + 2 && curr[-3] == ' ')
- X {
- X /*
- X * Special case for magic cookie terminals:
- X * if the previous char was a space, replace
- X * it with the "enter underline" sequence.
- X */
- X curr[-3] = UL_CHAR;
- X column += ul_width-1;
- X } else
- X {
- X curr[-1] = curr[-2];
- X curr[-2] = UL_CHAR;
- X column += ul_width;
- X curr++;
- X }
- X goto ln_ul_xb_case;
- X /*NOTREACHED*/
- X case LN_UL_XB:
- X /*
- X * Termination of a sequence "_\bX" or "X\b_".
- X */
- X if (c != '_' && curr[-2] != '_' && c == curr[-2])
- X {
- X /*
- X * We seem to have run on from underlining
- X * into boldfacing - this is a nasty fix, but
- X * until this whole routine is rewritten as a
- X * real DFA, ... well ...
- X */
- X curr[0] = curr[-2];
- X curr[-2] = UE_CHAR;
- X curr[-1] = BO_CHAR;
- X curr += 2; /* char & non-existent backspace */
- X ln_state = LN_BO_XB;
- X goto ln_bo_xb_case;
- X }
- Xln_ul_xb_case:
- X if (c == '_')
- X c = curr[-2];
- X curr -= 2;
- X ln_state = LN_UNDERLINE;
- X break;
- X case LN_BO_XB:
- X /*
- X * Termination of a sequnce "X\bX".
- X */
- X if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
- X {
- X /*
- X * We seem to have run on from
- X * boldfacing into underlining.
- X */
- X curr[0] = curr[-2];
- X curr[-2] = BE_CHAR;
- X curr[-1] = UL_CHAR;
- X curr += 2; /* char & non-existent backspace */
- X ln_state = LN_UL_XB;
- X goto ln_ul_xb_case;
- X }
- Xln_bo_xb_case:
- X curr -= 2;
- X ln_state = LN_BOLDFACE;
- X break;
- X case LN_UNDERLINE:
- X if (column + ue_width + bo_width + 1 + be_width >= sc_width)
- X /*
- X * We have just barely enough room to
- X * exit underline mode and handle a possible
- X * underline/boldface run on mixup.
- X */
- X return (1);
- X ln_state = LN_UL_X;
- X break;
- X case LN_BOLDFACE:
- X if (c == '\b')
- X {
- X ln_state = LN_BO_XB;
- X break;
- X }
- X if (column + be_width + ul_width + 1 + ue_width >= sc_width)
- X /*
- X * We have just barely enough room to
- X * exit underline mode and handle a possible
- X * underline/boldface run on mixup.
- X */
- X return (1);
- X ln_state = LN_BO_X;
- X break;
- X case LN_UL_X:
- X if (c == '\b')
- X ln_state = LN_UL_XB;
- X else
- X {
- X /*
- X * Exit underline mode.
- X * We have to shuffle the chars a bit
- X * to make this work.
- X */
- X curr[0] = curr[-1];
- X curr[-1] = UE_CHAR;
- X column += ue_width;
- X if (ue_width > 0 && curr[0] == ' ')
- X /*
- X * Another special case for magic
- X * cookie terminals: if the next
- X * char is a space, replace it
- X * with the "exit underline" sequence.
- X */
- X column--;
- X else
- X curr++;
- X ln_state = LN_NORMAL;
- X }
- X break;
- X case LN_BO_X:
- X if (c == '\b')
- X ln_state = LN_BO_XB;
- X else
- X {
- X /*
- X * Exit boldface mode.
- X * We have to shuffle the chars a bit
- X * to make this work.
- X */
- X curr[0] = curr[-1];
- X curr[-1] = BE_CHAR;
- X column += be_width;
- X if (be_width > 0 && curr[0] == ' ')
- X /*
- X * Another special case for magic
- X * cookie terminals: if the next
- X * char is a space, replace it
- X * with the "exit boldface" sequence.
- X */
- X column--;
- X else
- X curr++;
- X ln_state = LN_NORMAL;
- X }
- X break;
- X }
- X }
- X
- X if (c == '\t')
- X {
- X /*
- X * Expand a tab into spaces.
- X */
- X do
- X {
- X NEW_COLUMN(column+1);
- X } while ((column % tabstop) != 0);
- X *curr++ = '\t';
- X return (0);
- X }
- X
- X if (c == '\b')
- X {
- X if (bs_mode == BS_CONTROL)
- X {
- X /*
- X * Treat backspace as a control char: output "^H".
- X */
- X NEW_COLUMN(column+2);
- X *curr++ = ('H' | 0200);
- X } else
- X {
- X /*
- X * Output a real backspace.
- X */
- X column--;
- X *curr++ = '\b';
- X }
- X return (0);
- X }
- X
- X if (control_char(c))
- X {
- X /*
- X * Put a "^X" into the buffer.
- X * The 0200 bit is used to tell put_line() to prefix
- X * the char with a ^. We don't actually put the ^
- X * in the buffer because we sometimes need to move
- X * chars around, and such movement might separate
- X * the ^ from its following character.
- X * {{ This should be redone so that we can use an
- X * 8 bit (e.g. international) character set. }}
- X */
- X NEW_COLUMN(column+2);
- X *curr++ = (carat_char(c) | 0200);
- X return (0);
- X }
- X
- X /*
- X * Ordinary character. Just put it in the buffer.
- X */
- X NEW_COLUMN(column+1);
- X *curr++ = c;
- X return (0);
- X}
- X
- X/*
- X * Analogous to forw_line(), but deals with "raw lines":
- X * lines which are not split for screen width.
- X * {{ This is supposed to be more efficient than forw_line(). }}
- X */
- X public POSITION
- Xforw_raw_line(curr_pos)
- X POSITION curr_pos;
- X{
- X register char *p;
- X register int c;
- X POSITION new_pos;
- X
- X if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
- X (c = ch_forw_get()) == EOF)
- X return (NULL_POSITION);
- X
- X p = linebuf;
- X
- X for (;;)
- X {
- X if (c == '\n' || c == EOF)
- X {
- X new_pos = ch_tell();
- X break;
- X }
- X if (p >= &linebuf[sizeof(linebuf)-1])
- X {
- X /*
- X * Overflowed the input buffer.
- X * Pretend the line ended here.
- X * {{ The line buffer is supposed to be big
- X * enough that this never happens. }}
- X */
- X new_pos = ch_tell() - 1;
- X break;
- X }
- X *p++ = c;
- X c = ch_forw_get();
- X }
- X *p = '\0';
- X line = linebuf;
- X return (new_pos);
- X}
- X
- X/*
- X * Analogous to back_line(), but deals with "raw lines".
- X * {{ This is supposed to be more efficient than back_line(). }}
- X */
- X public POSITION
- Xback_raw_line(curr_pos)
- X POSITION curr_pos;
- X{
- X register char *p;
- X register int c;
- X POSITION new_pos;
- X
- X if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
- X ch_seek(curr_pos-1))
- X return (NULL_POSITION);
- X
- X p = &linebuf[sizeof(linebuf)];
- X *--p = '\0';
- X
- X for (;;)
- X {
- X c = ch_back_get();
- X if (c == '\n')
- X {
- X /*
- X * This is the newline ending the previous line.
- X * We have hit the beginning of the line.
- X */
- X new_pos = ch_tell() + 1;
- X break;
- X }
- X if (c == EOF)
- X {
- X /*
- X * We have hit the beginning of the file.
- X * This must be the first line in the file.
- X * This must, of course, be the beginning of the line.
- X */
- X new_pos = (POSITION)0;
- X break;
- X }
- X if (p <= linebuf)
- X {
- X /*
- X * Overflowed the input buffer.
- X * Pretend the line ended here.
- X */
- X new_pos = ch_tell() + 1;
- X break;
- X }
- X *--p = c;
- X }
- X line = p;
- X return (new_pos);
- X}
- SHAR_EOF
- fi
- if test -f 'main.c'
- then
- echo shar: "will not over-write existing file 'main.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'main.c'
- X/*
- X * Entry point, initialization, miscellaneous routines.
- X */
- X
- X#include "less.h"
- X#include "position.h"
- X#include <setjmp.h>
- X
- Xpublic int ispipe;
- Xpublic jmp_buf main_loop;
- Xpublic char * first_cmd;
- Xpublic char * every_first_cmd;
- Xpublic int new_file;
- Xpublic int is_tty;
- Xpublic char current_file[128];
- Xpublic int any_display;
- Xpublic int ac;
- Xpublic char ** av;
- Xpublic int curr_ac;
- X#if LOGFILE
- Xpublic int logfile = -1;
- Xpublic char * namelogfile = NULL;
- X#endif
- X#if EDITOR
- Xpublic char * editor;
- X#endif
- X
- Xextern int file;
- Xextern int nbufs;
- Xextern int sigs;
- Xextern int quit_at_eof;
- Xextern int p_nbufs, f_nbufs;
- Xextern int back_scroll;
- Xextern int top_scroll;
- Xextern int sc_height;
- Xextern int errmsgs;
- X
- X
- X/*
- X * Edit a new file.
- X * Filename "-" means standard input.
- X * No filename means the "current" file, from the command line.
- X */
- X public void
- Xedit(filename)
- X char *filename;
- X{
- X register int f;
- X char message[100];
- X static didpipe;
- X
- X if (filename == NULL || *filename == '\0')
- X {
- X if (curr_ac >= ac)
- X {
- X error("No current file");
- X return;
- X }
- X filename = av[curr_ac];
- X }
- X if (strcmp(filename, "-") == 0)
- X {
- X /*
- X * Use standard input.
- X */
- X if (didpipe)
- X {
- X error("Can view standard input only once");
- X return;
- X }
- X f = 0;
- X } else if ((f = open(filename, 0)) < 0)
- X {
- X static char co[] = "Cannot open ";
- X strcpy(message, co);
- X strtcpy(message+sizeof(co)-1, filename,
- X sizeof(message)-sizeof(co));
- X error(message);
- X return;
- X }
- X
- X if (isatty(f))
- X {
- X /*
- X * Not really necessary to call this an error,
- X * but if the control terminal (for commands)
- X * and the input file (for data) are the same,
- X * we get weird results at best.
- X */
- X error("Can't take input from a terminal");
- X if (f > 0)
- X close(f);
- X return;
- X }
- X
- X#if LOGFILE
- X /*
- X * If he asked for a log file and we have opened standard input,
- X * create the log file.
- X * We take care not to blindly overwrite an existing file.
- X */
- X end_logfile();
- X if (f == 0 && namelogfile != NULL && is_tty)
- X {
- X int exists;
- X int answer;
- X
- X /*
- X * {{ We could use access() here. }}
- X */
- X exists = open(namelogfile, 0);
- X close(exists);
- X exists = (exists >= 0);
- X
- X if (exists)
- X {
- X static char w[] = "WARNING: log file exists: ";
- X strcpy(message, w);
- X strtcpy(message+sizeof(w)-1, namelogfile,
- X sizeof(message)-sizeof(w));
- X error(message);
- X answer = 'X'; /* Ask the user what to do */
- X } else
- X answer = 'O'; /* Create the log file */
- X
- X loop:
- X switch (answer)
- X {
- X case 'O': case 'o':
- X logfile = creat(namelogfile, 0644);
- X break;
- X case 'A': case 'a':
- X logfile = open(namelogfile, 1);
- X if (lseek(logfile, (off_t)0, 2) < 0)
- X {
- X close(logfile);
- X logfile = -1;
- X }
- X break;
- X case 'D': case 'd':
- X answer = 0; /* Don't print an error message */
- X break;
- X case 'q':
- X quit();
- X default:
- X puts("\n Overwrite, Append, or Don't log? ");
- X answer = getc();
- X puts("\n");
- X flush();
- X goto loop;
- X }
- X
- X if (logfile < 0 && answer != 0)
- X {
- X sprintf(message, "Cannot write to \"%s\"",
- X namelogfile);
- X error(message);
- X }
- X }
- X#endif
- X
- X /*
- X * We are now committed to using the new file.
- X * Close the current input file and set up to use the new one.
- X */
- X if (file > 0)
- X close(file);
- X new_file = 1;
- X strtcpy(current_file, filename, sizeof(current_file));
- X ispipe = (f == 0);
- X if (ispipe)
- X didpipe = 1;
- X file = f;
- X ch_init( (ispipe) ? p_nbufs : f_nbufs );
- X init_mark();
- X
- X if (every_first_cmd != NULL)
- X first_cmd = every_first_cmd;
- X
- X if (is_tty)
- X {
- X int no_display = !any_display;
- X any_display = 1;
- X if (no_display && errmsgs > 0)
- X {
- X /*
- X * We displayed some messages on error output
- X * (file descriptor 2; see error() function).
- X * Before erasing the screen contents,
- X * display the file name and wait for a keystroke.
- X */
- X error(filename);
- X }
- X /*
- X * Indicate there is nothing displayed yet.
- X */
- X pos_clear();
- X }
- X}
- X
- X/*
- X * Edit the next file in the command line list.
- X */
- X public void
- Xnext_file(n)
- X int n;
- X{
- X if (curr_ac + n >= ac)
- X {
- X if (quit_at_eof)
- X quit();
- X error("No (N-th) next file");
- X } else
- X edit(av[curr_ac += n]);
- X}
- X
- X/*
- X * Edit the previous file in the command line list.
- X */
- X public void
- Xprev_file(n)
- X int n;
- X{
- X if (curr_ac - n < 0)
- X error("No (N-th) previous file");
- X else
- X edit(av[curr_ac -= n]);
- X}
- X
- X/*
- X * Copy a file directly to standard output.
- X * Used if standard output is not a tty.
- X */
- X static void
- Xcat_file()
- X{
- X register int c;
- X
- X while ((c = ch_forw_get()) != EOF)
- X putc(c);
- X flush();
- X}
- X
- X/*
- X * Entry point.
- X */
- Xmain(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X char *getenv();
- X
- X
- X /*
- X * Process command line arguments and LESS environment arguments.
- X * Command line arguments override environment arguments.
- X */
- X init_option();
- X scan_option(getenv("LESS"));
- X argv++;
- X while ( (--argc > 0) &&
- X (argv[0][0] == '-' || argv[0][0] == '+') &&
- X argv[0][1] != '\0')
- X scan_option(*argv++);
- X
- X#if EDITOR
- X editor = getenv("EDITOR");
- X if (editor == NULL || *editor == '\0')
- X editor = EDIT_PGM;
- X#endif
- X
- X /*
- X * Set up list of files to be examined.
- X */
- X ac = argc;
- X av = argv;
- X curr_ac = 0;
- X
- X /*
- X * Set up terminal, etc.
- X */
- X is_tty = isatty(1);
- X if (!is_tty)
- X {
- X /*
- X * Output is not a tty.
- X * Just copy the input file(s) to output.
- X */
- X if (ac < 1)
- X {
- X edit("-");
- X cat_file();
- X } else
- X {
- X do
- X {
- X edit((char *)NULL);
- X if (file >= 0)
- X cat_file();
- X } while (++curr_ac < ac);
- X }
- X exit(0);
- X }
- X
- X raw_mode(1);
- X get_term();
- X open_getc();
- X init();
- X
- X if (setjmp(main_loop))
- X quit();
- X init_signals();
- X
- X /*
- X * Select the first file to examine.
- X */
- X if (ac < 1)
- X edit("-"); /* Standard input */
- X else
- X {
- X /*
- X * Try all the files named as command arguments.
- X * We are simply looking for one which can be
- X * opened without error.
- X */
- X do
- X {
- X edit((char *)NULL);
- X } while (file < 0 && ++curr_ac < ac);
- X }
- X
- X if (file >= 0)
- X commands();
- X quit();
- X}
- X
- X/*
- X * Copy a string, truncating to the specified length if necessary.
- X * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
- X */
- Xstrtcpy(to, from, len)
- X char *to;
- X char *from;
- X int len;
- X{
- X strncpy(to, from, len);
- X to[len-1] = '\0';
- X}
- X
- X/*
- X * Exit the program.
- X */
- X public void
- Xquit()
- X{
- X /*
- X * Put cursor at bottom left corner, clear the line,
- X * reset the terminal modes, and exit.
- X */
- X#if LOGFILE
- X end_logfile();
- X#endif
- X lower_left();
- X clear_eol();
- X deinit();
- X flush();
- X raw_mode(0);
- X exit(0);
- X}
- SHAR_EOF
- fi
- if test -f 'makefile'
- then
- echo shar: "will not over-write existing file 'makefile'"
- else
- sed 's/^X//' << \SHAR_EOF > 'makefile'
- X# Makefile for "less"
- X#
- X# Invoked as:
- X# make all
- X# or make install
- X# Plain "make" is equivalent to "make all".
- X#
- X# If you add or delete functions, remake funcs.h by doing:
- X# make newfuncs
- X# This depends on the coding convention of function headers looking like:
- X# " \t public <function-type> \n <function-name> ( ... ) "
- X#
- X# Also provided:
- X# make lint # Runs "lint" on all the sources.
- X# make clean # Removes "less" and the .o files.
- X# make clobber # Pretty much the same as make "clean".
- X
- X
- X##########################################################################
- X# System-specific parameters
- X##########################################################################
- X
- X# Define XENIX if running under XENIX 3.0
- XXENIX = 0
- X
- X# VOID is 1 if your C compiler supports the "void" type,
- X# 0 if it does not.
- XVOID = 1
- X
- X# off_t is the type which lseek() returns.
- X# It is also the type of lseek()'s second argument.
- Xoff_t = long
- X
- X# TERMIO is 1 if your system has /usr/include/termio.h.
- X# This is normally the case for System 5.
- X# If TERMIO is 0 your system must have /usr/include/sgtty.h.
- X# This is normally the case for BSD.
- XTERMIO = 0
- X
- X# SIGSETMASK is 1 if your system has the sigsetmask() call.
- X# This is normally the case only for BSD 4.2,
- X# not for BSD 4.1 or System 5.
- XSIGSETMASK = 1
- X
- X##########################################################################
- X# Optional and semi-optional features
- X##########################################################################
- X
- X# REGCMP is 1 if your system has the regcmp() function.
- X# This is normally the case for System 5.
- X# RECOMP is 1 if your system has the re_comp() function.
- X# This is normally the case for BSD.
- X# If neither is 1, pattern matching is supported, but without metacharacters.
- XREGCMP = 0
- XRECOMP = 1
- X
- X# SHELL_ESCAPE is 1 if you wish to allow shell escapes.
- X# (This is possible only if your system supplies the system() function.)
- XSHELL_ESCAPE = 1
- X
- X# EDITOR is 1 if you wish to allow editor invocation (the "v" command).
- X# (This is possible only if your system supplies the system() function.)
- X# EDIT_PGM is the name of the (default) editor to be invoked.
- XEDITOR = 1
- XEDIT_PGM = vi
- X
- X# GLOB is 1 if you wish to have shell metacharacters expanded in filenames.
- X# This will generally work if your system provides the "popen" function
- X# and the "echo" shell command.
- XGLOB = 1
- X
- X# LOGFILE is 1 if you wish to allow the -l option (to create log files).
- XLOGFILE = 1
- X
- X# ONLY_RETURN is 1 if you want RETURN to be the only input which
- X# will continue past an error message.
- X# Otherwise, any key will continue past an error message.
- XONLY_RETURN = 0
- X
- X
- X##########################################################################
- X# Compilation environment.
- X##########################################################################
- X
- X# LIBS is the list of libraries needed.
- XLIBS = -ltermcap
- X
- X# INSTALL_LESS is a list of the public versions of less.
- X# INSTALL_HELP is a list of the public version of the help file.
- X# INSTALL_MAN is a list of the public versions of the manual page.
- XINSTALL_LESS = /usr/local/less
- XINSTALL_HELP = /usr/local/lib/less.help
- XINSTALL_MAN = /usr/local/man/cat1/less.0
- XMANUAL = less.nro
- XHELPFILE = /usr/local/lib/less.help
- X
- X
- X# OPTIM is passed to the compiler and the loader.
- X# It is normally "-O" but may be, for example, "-g".
- XOPTIM = -O -i
- X
- X
- X##########################################################################
- X# Files
- X##########################################################################
- X
- XSRC1 = main.c option.c prim.c ch.c position.c input.c output.c
- XSRC2 = screen.c prompt.c line.c signal.c help.c ttyin.c command.c version.c
- XSRC = $(SRC1) $(SRC2)
- XOBJ = main.o option.o prim.o ch.o position.o input.o output.o screen.o \
- X prompt.o line.o signal.o help.o ttyin.o command.o version.o
- X
- X
- X##########################################################################
- X# Rules
- X##########################################################################
- X
- XDEFS = "-DTERMIO=$(TERMIO)" \
- X "-DSIGSETMASK=$(SIGSETMASK)" \
- X "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
- X "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
- X "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
- X "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
- X "-DHELPFILE=\"$(HELPFILE)\"" \
- X "-DLOGFILE=$(LOGFILE)" \
- X "-DONLY_RETURN=$(ONLY_RETURN)" \
- X "-DGLOB=$(GLOB)" \
- X "-DXENIX=$(XENIX)"
- X
- XCFLAGS = $(OPTIM) $(DEFS)
- X
- X
- Xall: less
- X
- Xless: $(OBJ)
- X cc $(OPTIM) -o less $(OBJ) $(LIBS)
- X
- Xinstall: install_man install_less install_help
- X
- Xinstall_less: less
- X for f in $(INSTALL_LESS); do rm -f $$f; cp less $$f; done
- X touch install_less
- X
- Xinstall_help: less.help
- X for f in $(INSTALL_HELP); do rm -f $$f; cp less.help $$f; done
- X touch install_help
- X
- Xinstall_man: $(MANUAL)
- X rm -f $(INSTALL_MAN)
- X /usr/man/manroff $(MANUAL) > $(INSTALL_MAN)
- X chmod 444 $(INSTALL_MAN)
- X chown bin.bin $(INSTALL_MAN)
- X touch install_man
- X
- X$(OBJ): less.h funcs.h
- X
- X# help.o depends on makefile for the definition of HELPFILE.
- Xhelp.o: makefile
- X
- Xlint:
- X lint -hp $(DEFS) $(SRC)
- X
- Xnewfuncs:
- X mv funcs.h funcs.h.OLD
- X awk -f mkfuncs.awk $(SRC) >funcs.h
- X
- Xclean:
- X rm -f $(OBJ) less install_help install_less install_man core
- X
- Xclobber:
- X rm -f *.o less install_less install_man
- X
- Xshar:
- X shar -v README install less.man less.help makefile.* *.h *.awk > less.shar.a
- X shar -v less.nro $(SRC1) > less.shar.b
- X shar -v $(SRC2) > less.shar.c
- SHAR_EOF
- fi
- if test -f 'mkfuncs.awk'
- then
- echo shar: "will not over-write existing file 'mkfuncs.awk'"
- else
- sed 's/^X//' << \SHAR_EOF > 'mkfuncs.awk'
- XBEGIN { FS="("; state = 0 }
- X
- X/^ public/ { ftype = $0; state = 1 }
- X
- X{ if (state == 1)
- X state = 2
- X else if (state == 2)
- X { print ftype,$1,"();"; state = 0 }
- X}
- SHAR_EOF
- fi
- if test -f 'option.c'
- then
- echo shar: "will not over-write existing file 'option.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'option.c'
- X/*
- X * Process command line options.
- X * Each option is a single letter which controls a program variable.
- X * The options have defaults which may be changed via
- X * the command line option, or toggled via the "-" command.
- X */
- X
- X#include "less.h"
- X
- X#define toupper(c) ((c)-'a'+'A')
- X
- X#define END_OPTION_STRING ('$')
- X
- X/*
- X * Types of options.
- X */
- X#define BOOL 01 /* Boolean option: 0 or 1 */
- X#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */
- X#define NUMBER 04 /* Numeric option */
- X#define REPAINT 040 /* Repaint screen after toggling option */
- X#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */
- X
- X/*
- X * Variables controlled by command line options.
- X */
- Xpublic int p_nbufs, f_nbufs; /* Number of buffers. There are two values,
- X one used for input from a pipe and
- X the other for input from a file. */
- Xpublic int clean_data; /* Can we assume the data is "clean"?
- X (That is, free of nulls, etc) */
- Xpublic int quiet; /* Should we suppress the audible bell? */
- Xpublic int top_search; /* Should forward searches start at the top
- X of the screen? (alternative is bottom) */
- Xpublic int top_scroll; /* Repaint screen from top?
- X (alternative is scroll from bottom) */
- Xpublic int pr_type; /* Type of prompt (short, medium, long) */
- Xpublic int bs_mode; /* How to process backspaces */
- Xpublic int know_dumb; /* Don't complain about dumb terminals */
- Xpublic int quit_at_eof; /* Quit after hitting end of file twice */
- Xpublic int squeeze; /* Squeeze multiple blank lines into one */
- Xpublic int tabstop; /* Tab settings */
- Xpublic int back_scroll; /* Repaint screen on backwards movement */
- Xpublic int twiddle; /* Display "~" for lines after EOF */
- X
- Xextern char *prproto[];
- Xextern int nbufs;
- Xextern int sc_window;
- Xextern char *first_cmd;
- Xextern char *every_first_cmd;
- X#if LOGFILE
- Xextern char *namelogfile;
- X#endif
- X
- X#define DEF_F_NBUFS 5 /* Default for f_nbufs */
- X#define DEF_P_NBUFS 12 /* Default for p_nbufs */
- X
- Xstatic struct option
- X{
- X char oletter; /* The controlling letter (a-z) */
- X char otype; /* Type of the option */
- X int odefault; /* Default value */
- X int *ovar; /* Pointer to the associated variable */
- X char *odesc[3]; /* Description of each value */
- X} option[] =
- X{
- X { 'c', BOOL, 0, &clean_data,
- X { "Don't assume data is clean",
- X "Assume data is clean",
- X NULL
- X }
- X },
- X { 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
- X { NULL, NULL, NULL}
- X },
- X { 'e', BOOL, 0, &quit_at_eof,
- X { "Don't quit at end-of-file",
- X "Quit at end-of-file",
- X NULL
- X }
- X },
- X { 'h', NUMBER, -1, &back_scroll,
- X { "Backwards scroll limit is %d lines",
- X NULL, NULL
- X }
- X },
- X { 'p', BOOL, 0, &top_scroll,
- X { "Repaint by scrolling from bottom of screen",
- X "Repaint by painting from top of screen",
- X NULL
- X }
- X },
- X { 'x', NUMBER, 8, &tabstop,
- X { "Tab stops every %d spaces",
- X NULL, NULL
- X }
- X },
- X { 's', BOOL|REPAINT, 0, &squeeze,
- X { "Don't squeeze multiple blank lines",
- X "Squeeze multiple blank lines",
- X NULL
- X }
- X },
- X { 't', BOOL, 1, &top_search,
- X { "Forward search starts from bottom of screen",
- X "Forward search starts from top of screen",
- X NULL
- X }
- X },
- X { 'w', BOOL|REPAINT, 1, &twiddle,
- X { "Display nothing for lines after end-of-file",
- X "Display ~ for lines after end-of-file",
- X NULL
- X }
- X },
- X { 'm', TRIPLE, 0, &pr_type,
- X { "Short prompt",
- X "Medium prompt",
- X "Long prompt"
- X }
- X },
- X { 'q', TRIPLE, 0, &quiet,
- X { "Ring the bell for errors AND at eof/bof",
- X "Ring the bell for errors but not at eof/bof",
- X "Never ring the bell"
- X }
- X },
- X { 'u', TRIPLE|REPAINT, 0, &bs_mode,
- X { "Underlined text displayed in underline mode",
- X "Backspaces cause overstrike",
- X "Backspaces print as ^H"
- X }
- X },
- X { 'z', NUMBER, 24, &sc_window,
- X { "Scroll window size is %d lines",
- X NULL, NULL
- X }
- X },
- X { '\0' }
- X};
- X
- Xpublic char all_options[64]; /* List of all valid options */
- X
- X/*
- X * Initialize each option to its default value.
- X */
- X public void
- Xinit_option()
- X{
- X register struct option *o;
- X register char *p;
- X
- X /*
- X * First do special cases, not in option table.
- X */
- X first_cmd = every_first_cmd = NULL;
- X f_nbufs = DEF_F_NBUFS; /* -bf */
- X p_nbufs = DEF_P_NBUFS; /* -bp */
- X
- X p = all_options;
- X *p++ = 'b';
- X
- X for (o = option; o->oletter != '\0'; o++)
- X {
- X /*
- X * Set each variable to its default.
- X * Also make a list of all options, in "all_options".
- X */
- X *(o->ovar) = o->odefault;
- X *p++ = o->oletter;
- X if (o->otype & TRIPLE)
- X *p++ = toupper(o->oletter);
- X }
- X *p = '\0';
- X}
- X
- X/*
- X * Toggle command line flags from within the program.
- X * Used by the "-" command.
- X */
- X public void
- Xtoggle_option(c)
- X int c;
- X{
- X register struct option *o;
- X char message[100];
- X char buf[5];
- X
- X /*
- X * First check for special cases not handled by the option table.
- X */
- X switch (c)
- X {
- X case 'b':
- X sprintf(message, "%d buffers", nbufs);
- X error(message);
- X return;
- X }
- X
- X
- X for (o = option; o->oletter != '\0'; o++)
- X {
- X if (o->otype & NO_TOGGLE)
- X continue;
- X if ((o->otype & BOOL) && (o->oletter == c))
- X {
- X /*
- X * Boolean option:
- X * just toggle it.
- X */
- X *(o->ovar) = ! *(o->ovar);
- X } else if ((o->otype & TRIPLE) && (o->oletter == c))
- X {
- X /*
- X * Triple-valued option with lower case letter:
- X * make it 1 unless already 1, then make it 0.
- X */
- X *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
- X } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
- X {
- X /*
- X * Triple-valued option with upper case letter:
- X * make it 2 unless already 2, then make it 0.
- X */
- X *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
- X } else if ((o->otype & NUMBER) && (o->oletter == c))
- X {
- X sprintf(message, o->odesc[0],
- X (o->ovar == &back_scroll) ?
- X get_back_scroll() : *(o->ovar));
- X error(message);
- X return;
- X } else
- X continue;
- X
- X if (o->otype & REPAINT)
- X repaint();
- X error(o->odesc[*(o->ovar)]);
- X return;
- X }
- X
- X if (control_char(c))
- X sprintf(buf, "^%c", carat_char(c));
- X else
- X sprintf(buf, "%c", c);
- X sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"",
- X buf, all_options);
- X error(message);
- X}
- X
- X/*
- X * Scan to end of string or to an END_OPTION_STRING character.
- X * In the latter case, replace the char with a null char.
- X * Return a pointer to the remainder of the string, if any.
- X */
- X static char *
- Xoptstring(s)
- X char *s;
- X{
- X register char *p;
- X
- X for (p = s; *p != '\0'; p++)
- X if (*p == END_OPTION_STRING)
- X {
- X *p = '\0';
- X return (p+1);
- X }
- X return (p);
- X}
- X
- X/*
- X * Scan an argument (either from command line or from LESS environment
- X * variable) and process it.
- X */
- X public void
- Xscan_option(s)
- X char *s;
- X{
- X register struct option *o;
- X register int c;
- X char message[80];
- X
- X if (s == NULL)
- X return;
- X
- X next:
- X if (*s == '\0')
- X return;
- X switch (c = *s++)
- X {
- X case '-':
- X case ' ':
- X case '\t':
- X case END_OPTION_STRING:
- X goto next;
- X case '+':
- X if (*s == '+')
- X every_first_cmd = ++s;
- X first_cmd = s;
- X s = optstring(s);
- X goto next;
- X case 'P':
- X switch (*s)
- X {
- X case 'm': prproto[PR_MEDIUM] = ++s; break;
- X case 'M': prproto[PR_LONG] = ++s; break;
- X default: prproto[PR_SHORT] = s; break;
- X }
- X s = optstring(s);
- X goto next;
- X#if LOGFILE
- X case 'l':
- X namelogfile = s;
- X s = optstring(s);
- X goto next;
- X#endif
- X case 'b':
- X switch (*s)
- X {
- X case 'f':
- X s++;
- X f_nbufs = getnum(&s, 'b');
- X break;
- X case 'p':
- X s++;
- X p_nbufs = getnum(&s, 'b');
- X break;
- X default:
- X f_nbufs = p_nbufs = getnum(&s, 'b');
- X break;
- X }
- X goto next;
- X case '0': case '1': case '2': case '3': case '4':
- X case '5': case '6': case '7': case '8': case '9':
- X {
- X /*
- X * Handle special "more" compatibility form "-number"
- X * to set the scrolling window size.
- X */
- X s--;
- X sc_window = getnum(&s, '-');
- X goto next;
- X }
- X }
- X
- X for (o = option; o->oletter != '\0'; o++)
- X {
- X if ((o->otype & BOOL) && (o->oletter == c))
- X {
- X *(o->ovar) = ! o->odefault;
- X goto next;
- X } else if ((o->otype & TRIPLE) && (o->oletter == c))
- X {
- X *(o->ovar) = (o->odefault == 1) ? 0 : 1;
- X goto next;
- X } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
- X {
- X *(o->ovar) = (o->odefault == 2) ? 0 : 2;
- X goto next;
- X } else if ((o->otype & NUMBER) && (o->oletter == c))
- X {
- X *(o->ovar) = getnum(&s, c);
- X goto next;
- X }
- X }
- X
- X sprintf(message, "\"-%c\": invalid flag", c);
- X error(message);
- X exit(1);
- X}
- X
- X/*
- X * Translate a string into a number.
- X * Like atoi(), but takes a pointer to a char *, and updates
- X * the char * to point after the translated number.
- X */
- X static int
- Xgetnum(sp, c)
- X char **sp;
- X int c;
- X{
- X register char *s;
- X register int n;
- X char message[80];
- X
- X s = *sp;
- X if (*s < '0' || *s > '9')
- X {
- X sprintf(message, "number is required after -%c", c);
- X error(message);
- X exit(1);
- X }
- X
- X n = 0;
- X while (*s >= '0' && *s <= '9')
- X n = 10 * n + *s++ - '0';
- X *sp = s;
- X return (n);
- X}
- SHAR_EOF
- fi
- if test -f 'output.c'
- then
- echo shar: "will not over-write existing file 'output.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'output.c'
- X/*
- X * High level routines dealing with the output to the screen.
- X */
- X
- X#include "less.h"
- X
- Xpublic int errmsgs; /* Count of messages displayed by error() */
- X
- Xextern int sigs;
- Xextern int sc_width, sc_height;
- Xextern int ul_width, ue_width;
- Xextern int so_width, se_width;
- Xextern int bo_width, be_width;
- Xextern int tabstop;
- Xextern int twiddle;
- Xextern int any_display;
- Xextern char *line;
- Xextern char *first_cmd;
- X
- X/*
- X * Display the line which is in the line buffer.
- X */
- X public void
- Xput_line()
- X{
- X register char *p;
- X register int c;
- X register int column;
- X extern int auto_wrap, ignaw;
- X
- X if (sigs)
- X /*
- X * Don't output if a signal is pending.
- X */
- X return;
- X
- X if (line == NULL)
- X line = (twiddle) ? "~" : "";
- X
- X column = 0;
- X for (p = line; *p != '\0'; p++)
- X {
- X switch (c = *p)
- X {
- X case UL_CHAR:
- X ul_enter();
- X column += ul_width;
- X break;
- X case UE_CHAR:
- X ul_exit();
- X column += ue_width;
- X break;
- X case BO_CHAR:
- X bo_enter();
- X column += bo_width;
- X break;
- X case BE_CHAR:
- X bo_exit();
- X column += be_width;
- X break;
- X case '\t':
- X do
- X {
- X putc(' ');
- X column++;
- X } while ((column % tabstop) != 0);
- X break;
- X case '\b':
- X putbs();
- X column--;
- X break;
- X default:
- X if (c & 0200)
- X {
- X putc('^');
- X putc(c & 0177);
- X column += 2;
- X } else
- X {
- X putc(c);
- X column++;
- X }
- X }
- X }
- X if (column < sc_width || !auto_wrap || ignaw)
- X putc('\n');
- X}
- X
- X/*
- X * Is a given character a "control" character?
- X * {{ ASCII DEPENDENT }}
- X */
- X public int
- Xcontrol_char(c)
- X int c;
- X{
- X return (c < ' ' || c == '\177');
- X}
- X
- X/*
- X * Return the printable character used to identify a control character
- X * (printed after a carat; e.g. '\3' => "^C").
- X * {{ ASCII DEPENDENT }}
- X */
- X public int
- Xcarat_char(c)
- X int c;
- X{
- X return ((c == '\177') ? '?' : (c | 0100));
- X}
- X
- X
- Xstatic char obuf[1024];
- Xstatic char *ob = obuf;
- X
- X/*
- X * Flush buffered output.
- X */
- X public void
- Xflush()
- X{
- X write(1, obuf, ob-obuf);
- X ob = obuf;
- X}
- X
- X/*
- X * Discard buffered output.
- X */
- X public void
- Xdropout()
- X{
- X ob = obuf;
- X}
- X
- X/*
- X * Output a character.
- X */
- X public void
- Xputc(c)
- X int c;
- X{
- X if (ob >= &obuf[sizeof(obuf)])
- X flush();
- X *ob++ = c;
- X}
- X
- X/*
- X * Output a string.
- X */
- X public void
- Xputs(s)
- X register char *s;
- X{
- X while (*s != '\0')
- X putc(*s++);
- X}
- X
- X/*
- X * Output a message in the lower left corner of the screen
- X * and wait for carriage return.
- X */
- X
- Xstatic char return_to_continue[] = " (press RETURN)";
- X
- X public void
- Xerror(s)
- X char *s;
- X{
- X register int c;
- X static char buf[2];
- X
- X errmsgs++;
- X if (!any_display)
- X {
- X /*
- X * Nothing has been displayed yet.
- X * Output this message on error output (file
- X * descriptor 2) and don't wait for a keystroke
- X * to continue.
- X *
- X * This has the desirable effect of producing all
- X * error messages on error output if standard output
- X * is directed to a file. It also does the same if
- X * we never produce any real output; for example, if
- X * the input file(s) cannot be opened. If we do
- X * eventually produce output, code in edit() makes
- X * sure these messages can be seen before they are
- X * overwritten or scrolled away.
- X */
- X write(2, s, strlen(s));
- X write(2, "\n", 1);
- X return;
- X }
- X
- X lower_left();
- X clear_eol();
- X so_enter();
- X puts(s);
- X puts(return_to_continue);
- X so_exit();
- X
- X#if ONLY_RETURN
- X while ((c = getc()) != '\n' && c != '\r')
- X bell();
- X#else
- X c = getc();
- X if (c != '\n' && c != '\r' && c != ' ')
- X {
- X buf[0] = c;
- X first_cmd = buf;
- X }
- X#endif
- X
- X if (strlen(s) + sizeof(return_to_continue) +
- X so_width + se_width + 1 > sc_width)
- X /*
- X * Printing the message has probably scrolled the screen.
- X * {{ Unless the terminal doesn't have auto margins,
- X * in which case we just hammered on the right margin. }}
- X */
- X repaint();
- X}
- X
- X#ifdef notdef
- X public int
- Xerror_width()
- X{
- X /*
- X * Don't use the last position, because some terminals
- X * will scroll if you write in the last char of the last line.
- X */
- X return (sc_width -
- X (sizeof(return_to_continue) + so_width + se_width + 1));
- X}
- X#endif
- SHAR_EOF
- fi
- if test -f 'position.c'
- then
- echo shar: "will not over-write existing file 'position.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'position.c'
- X/*
- X * Routines dealing with the "position" table.
- X * This is a table which tells the position (in the input file) of the
- X * first char on each currently displayed line.
- X *
- X * {{ The position table is scrolled by moving all the entries.
- X * Would be better to have a circular table
- X * and just change a couple of pointers. }}
- X */
- X
- X#include "less.h"
- X#include "position.h"
- X
- X#define NPOS 100 /* {{ sc_height must be less than NPOS }} */
- Xstatic POSITION table[NPOS]; /* The position table */
- X
- Xextern int sc_width, sc_height;
- X
- X/*
- X * Return the starting file position of a line displayed on the screen.
- X * The line may be specified as a line number relative to the top
- X * of the screen, but is usually one of these special cases:
- X * the top (first) line on the screen
- X * the second line on the screen
- X * the bottom line on the screen
- X * the line after the bottom line on the screen
- X */
- X public POSITION
- Xposition(where)
- X int where;
- X{
- X switch (where)
- X {
- X case BOTTOM:
- X where = sc_height - 2;
- X break;
- X case BOTTOM_PLUS_ONE:
- X where = sc_height - 1;
- X break;
- X }
- X return (table[where]);
- X}
- X
- X/*
- X * Add a new file position to the bottom of the position table.
- X */
- X public void
- Xadd_forw_pos(pos)
- X POSITION pos;
- X{
- X register int i;
- X
- X /*
- X * Scroll the position table up.
- X */
- X for (i = 1; i < sc_height; i++)
- X table[i-1] = table[i];
- X table[sc_height - 1] = pos;
- X}
- X
- X/*
- X * Add a new file position to the top of the position table.
- X */
- X public void
- Xadd_back_pos(pos)
- X POSITION pos;
- X{
- X register int i;
- X
- X /*
- X * Scroll the position table down.
- X */
- X for (i = sc_height - 1; i > 0; i--)
- X table[i] = table[i-1];
- X table[0] = pos;
- X}
- X
- X/*
- X * Initialize the position table, done whenever we clear the screen.
- X */
- X public void
- Xpos_clear()
- X{
- X register int i;
- X
- X for (i = 0; i < sc_height; i++)
- X table[i] = NULL_POSITION;
- X}
- X
- X/*
- X * See if the byte at a specified position is currently on the screen.
- X * Check the position table to see if the position falls within its range.
- X * Return the position table entry if found, -1 if not.
- X */
- X public int
- Xonscreen(pos)
- X POSITION pos;
- X{
- X register int i;
- X
- X if (pos < table[0])
- X return (-1);
- X for (i = 1; i < sc_height; i++)
- X if (pos < table[i])
- X return (i-1);
- X return (-1);
- X}
- SHAR_EOF
- fi
- if test -f 'position.h'
- then
- echo shar: "will not over-write existing file 'position.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'position.h'
- X/*
- X * Include file for interfacing to position.c modules.
- X */
- X#define TOP 0
- X#define TOP_PLUS_ONE 1
- X#define BOTTOM -1
- X#define BOTTOM_PLUS_ONE -2
- SHAR_EOF
- fi
- if test -f 'prim.c'
- then
- echo shar: "will not over-write existing file 'prim.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'prim.c'
- 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 */
- X
- Xextern int quiet;
- Xextern int top_search;
- Xextern int top_scroll;
- Xextern int back_scroll;
- Xextern int sc_width, sc_height;
- Xextern int sigs;
- Xextern char *line;
- Xextern char *first_cmd;
- X
- X/*
- X * Sound the bell to indicate he 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 /*
- 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 * 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 repaint_flag;
- X static int first_time = 1;
- X
- X /*
- X * repaint_flag tells us not to display anything till the end,
- X * then just repaint the entire screen.
- X */
- X repaint_flag = (only_last && n > sc_height-1);
- X
- X if (!repaint_flag)
- 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 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 clear();
- X home();
- X } else if (!first_time)
- X {
- X puts("...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 line = NULL;
- 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 (repaint_flag ||
- X (first_time && line == NULL && !top_scroll))
- X continue;
- X put_line();
- X }
- X
- X if (eof)
- X hit_eof++;
- X else
- X eof_check();
- X if (nlines == 0)
- X eof_bell();
- X else if (repaint_flag)
- X repaint();
- X first_time = 0;
- 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 repaint_flag;
- X
- X repaint_flag = (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 line = NULL;
- 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 (!repaint_flag)
- 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 (repaint_flag)
- X repaint();
- 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 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 forw(sc_height-1, pos, 0, 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 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 register int n;
- X{
- X register int c;
- X int nlines;
- X
- X /*
- X * This is done the slow way, by starting at the beginning
- X * of the file and counting newlines.
- X */
- X if (ch_seek((POSITION)0))
- X {
- X /*
- X * Probably a pipe with beginning of file no longer buffered.
- X * If he wants to go to line 1, we do the best we can,
- X * by going to the first line which is still buffered.
- X */
- X if (n <= 1 && ch_beg_seek() == 0)
- X jump_loc(ch_tell());
- X error("Cannot get to beginning of file");
- X return;
- X }
- X
- X /*
- X * Start counting lines.
- X */
- X for (nlines = 1; nlines < n; nlines++)
- X {
- X while ((c = ch_forw_get()) != '\n')
- X if (c == EOF)
- X {
- X char message[40];
- X sprintf(message, "File has only %d lines",
- X nlines-1);
- X error(message);
- X return;
- X }
- X }
- X
- X jump_loc(ch_tell());
- 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 register int c;
- 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 /*
- X * Back up to the beginning of the line.
- X */
- X if (ch_seek(pos) == 0)
- X {
- X while ((c = ch_back_get()) != '\n' && c != EOF)
- 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 position in the file.
- X */
- X public void
- Xjump_loc(pos)
- X POSITION pos;
- X{
- X register int nline;
- X POSITION tpos;
- X
- X /*
- X * See if the desired line is BEFORE the currently
- X * displayed screen. If so, see if it is close enough
- X * to scroll backwards to it.
- X * {{ This can be expensive if he has specified a very
- X * large back_scroll count. Perhaps we should put
- X * some sanity limit on the loop count here. }}
- X */
- X tpos = position(TOP);
- X if (tpos != NULL_POSITION && pos < tpos)
- X {
- X int bs = get_back_scroll();
- X for (nline = 1; nline <= bs; nline++)
- X {
- X tpos = back_line(tpos);
- X if (tpos == NULL_POSITION)
- X break;
- X if (tpos <= pos)
- X {
- X back(nline, position(TOP), 1, 0);
- X return;
- X }
- X }
- X } else 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 * Remember where we were; clear and paint the screen.
- X */
- X if (ch_seek(pos))
- X {
- X error("Cannot seek to that position");
- X return;
- X }
- X lastmark();
- X prepaint(pos);
- X}
- X
- X/*
- X * The table of marks.
- X * A mark is simply a position in the file.
- X */
- X#define NMARKS (27) /* 26 for a-z plus one for quote */
- X#define LASTMARK (NMARKS-1) /* For quote */
- Xstatic POSITION 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] = 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 marks[c-'a'] = position(TOP);
- X}
- X
- X public void
- Xlastmark()
- X{
- X marks[LASTMARK] = position(TOP);
- X}
- X
- X/*
- X * Go to a previously set mark.
- X */
- X public void
- Xgomark(c)
- X int c;
- X{
- X POSITION pos;
- X
- X if (c == '\'')
- X pos = marks[LASTMARK];
- X else if (badmark(c))
- X return;
- X else
- X pos = marks[c-'a'];
- X
- X if (pos == NULL_POSITION)
- X error("mark not set");
- X else
- 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 (sc_height - 1 - top_scroll);
- X return (back_scroll);
- X}
- X
- X/*
- X * Search for the n-th occurence of a specified pattern,
- X * either forward (direction == '/'), or backwards (direction == '?').
- X */
- X public void
- Xsearch(direction, pattern, n)
- X int direction;
- X char *pattern;
- X register int n;
- X{
- X register int search_forward = (direction == '/');
- X POSITION pos, linepos;
- X
- X#if RECOMP
- X char *re_comp();
- X char *errmsg;
- 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 char *regcmp();
- X static char *cpattern = NULL;
- X
- 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 static char lpbuf[100];
- X static char *last_pattern = NULL;
- X
- 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 (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 } else if (!search_forward)
- X {
- X /*
- X * Backward search: start just before the top line
- X * displayed on the screen.
- X */
- X pos = position(TOP);
- X } else if (top_search)
- X {
- X /*
- X * Forward search and "start from top".
- X * Start at the second line displayed on the screen.
- X */
- X pos = position(TOP_PLUS_ONE);
- X } else
- X {
- X /*
- X * Forward search but don't "start from top".
- X * Start just after the bottom line displayed on the screen.
- X */
- X pos = position(BOTTOM_PLUS_ONE);
- 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 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 (search_forward)
- 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);
- 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);
- X linepos = pos;
- 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 * 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 if ( (regex(cpattern, line) != NULL)
- X#else
- X#if RECOMP
- X if ( (re_exec(line) == 1)
- X#else
- X if ( (match(pattern, line))
- X#endif
- X#endif
- X && (--n <= 0) )
- X /*
- X * Found the matching 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
- SHAR_EOF
- fi
- if test -f 'prompt.c'
- then
- echo shar: "will not over-write existing file 'prompt.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'prompt.c'
- 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 * A prompt is either a colon or a message composed of various
- X * pieces, such as the name of the file being viewed, the percentage
- X * 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 char current_file[];
- Xextern int ac;
- Xextern char **av;
- Xextern int curr_ac;
- X
- X/*
- X * Prototypes for the three flavors of prompts.
- X * These strings are expanded by pr_expand().
- X */
- Xchar *prproto[] = {
- X "fo", /* PR_SHORT */
- X "foP", /* PR_MEDIUM */
- X "Fobp" /* PR_LONG */
- X};
- X
- Xstatic char message[200];
- Xstatic char *mp;
- X
- X static void
- Xsetmp()
- X{
- X mp = message + strlen(message);
- X}
- X
- X/*
- X * Append the name of the current file (to the message buffer).
- X */
- X static void
- Xap_filename()
- X{
- X if (ispipe)
- X return;
- X strtcpy(mp, current_file, &message[sizeof(message)] - mp);
- X setmp();
- X}
- X
- X/*
- X * Append the "file N of M" message.
- X */
- X static void
- Xap_of()
- X{
- X if (ac <= 1)
- X return;
- X sprintf(mp, " (file %d of %d)", curr_ac+1, ac);
- X setmp();
- X}
- X
- X/*
- X * Append the byte offset into the current file.
- X */
- X static void
- Xap_byte()
- X{
- X POSITION pos, len;
- X
- X pos = position(BOTTOM_PLUS_ONE);
- X if (pos == NULL_POSITION)
- X pos = ch_length();
- X if (pos != NULL_POSITION)
- X {
- X sprintf(mp, " byte %ld", (long)pos);
- X setmp();
- X len = ch_length();
- X if (len > 0)
- X {
- X sprintf(mp, "/%ld", (long)len);
- X setmp();
- X }
- X }
- X}
- X
- X/*
- X * Append the percentage into the current file.
- X * If we cannot find the percentage and must_print is true,
- X * use the byte offset.
- X */
- X static void
- Xap_percent(must_print)
- X{
- X POSITION pos,len;
- X
- X pos = position(BOTTOM_PLUS_ONE);
- X len = ch_length();
- X if (len > 0 && pos != NULL_POSITION)
- X {
- X sprintf(mp, " (%ld%%)", (100 * (long)pos) / len);
- X setmp();
- X } else if (must_print)
- X ap_byte();
- X}
- X
- X/*
- X * Append the end-of-file message.
- X */
- X static void
- Xap_eof()
- X{
- X strcpy(mp, " (END)");
- X setmp();
- X if (curr_ac + 1 < ac)
- X {
- X sprintf(mp, " - Next: %s", av[curr_ac+1]);
- X setmp();
- X }
- X}
- X
- X/*
- X * Construct a message based on a prototype string.
- X */
- X static char *
- Xpr_expand(proto, maxwidth)
- X char *proto;
- X int maxwidth;
- X{
- X register char *p;
- X
- X mp = message;
- X
- X for (p = proto; *p != '\0'; p++)
- X {
- X if (maxwidth > 0 && mp >= message + maxwidth)
- X {
- X /*
- X * Truncate to the screen width.
- X * {{ This isn't very nice. }}
- X */
- X mp = message + maxwidth;
- X break;
- X }
- X switch (*p)
- X {
- X case 'f':
- X if (new_file)
- X ap_filename();
- X break;
- X case 'F':
- X ap_filename();
- X break;
- X case 'o':
- X if (new_file)
- X ap_of();
- X break;
- X case 'O':
- X ap_of();
- X break;
- X case 'b':
- X ap_byte();
- X break;
- X case 'p':
- X if (!hit_eof)
- X ap_percent(0);
- X break;
- X case 'P':
- X if (!hit_eof)
- X ap_percent(1);
- X break;
- X case '<':
- X while (*++p != '>')
- X {
- X if (*p == '\0')
- X {
- X p--;
- X break;
- X }
- X *mp++ = *p;
- X }
- X break;
- X default:
- X *mp++ = *p;
- X break;
- X }
- X }
- X if (hit_eof)
- X ap_eof();
- X
- X new_file = 0;
- X if (mp == message)
- X return (NULL);
- X *mp = '\0';
- 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("FObp", 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-2));
- X}
- SHAR_EOF
- fi
- if test -f 'screen.c'
- then
- echo shar: "will not over-write existing file 'screen.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'screen.c'
- 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/*
- 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-intialization */
- Xstatic int dumb;
- Xstatic int hard;
- 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 sc_window = -1; /* window size for forward and backward */
- 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
- 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;
- Xchar *tgetstr();
- Xchar *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 * He knows he has 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 termbuf[1024];
- X char *sp;
- X static char sbuf[150];
- X
- X char *getenv();
- X
- X /*
- X * Find out what kind of terminal this is.
- X */
- X if (tgetent(termbuf, getenv("TERM")) <= 0)
- X dumb = 1;
- X
- X /*
- X * Get size of the screen.
- X */
- X if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
- X {
- X /* Oh no, this is a hardcopy terminal. */
- X hard = 1;
- X sc_height = 24;
- X }
- X /*
- X * This is terrible - the following if "knows" that it is being
- X * executed *after* command line and environment options have
- X * already been parsed. Should it be executed in the main program
- X * instead?
- X */
- X if ((sc_window <= 0) || (sc_window >= sc_height))
- X sc_window = sc_height-1;
- X if (dumb || (sc_width = tgetnum("co")) < 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 = (dumb) ? NULL : tgetstr("pc", &sp);
- X if (sc_pad != NULL)
- X PC = *sc_pad;
- X
- X sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
- X if (sc_init == NULL)
- X sc_init = "";
- X
- X sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
- X if (sc_deinit == NULL)
- X sc_deinit = "";
- X
- X sc_eol_clear = (dumb) ? NULL : 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 = (dumb) ? NULL : 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 = (dumb) ? NULL : 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 = (dumb) ? NULL : tgetstr("so", &sp);
- X if (hard || sc_s_in == NULL)
- X sc_s_in = "";
- X
- X sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
- X if (hard || sc_s_out == NULL)
- X sc_s_out = "";
- X
- X sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
- X if (hard || sc_u_in == NULL)
- X sc_u_in = sc_s_in;
- X
- X sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
- X if (hard || sc_u_out == NULL)
- X sc_u_out = sc_s_out;
- X
- X sc_b_in = (dumb) ? NULL : 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 = (dumb) ? NULL : tgetstr("me", &sp);
- X if (hard || sc_b_out == NULL)
- X sc_b_out = "";
- X }
- X
- X sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
- X if (hard || sc_visual_bell == NULL)
- X sc_visual_bell = "";
- X
- X sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
- X if (hard || sc_home == NULL || *sc_home == '\0')
- X {
- X if (*sc_move == '\0')
- X {
- X cannot("home cursor");
- X /*
- X * This last resort for sc_home is supposed to
- X * be an up-arrow suggesting moving to the
- X * top of the "virtual screen". (The one in
- X * your imagination as you try to use this on
- X * a hard copy terminal.)
- X */
- X sc_home = "|\b^";
- X } else
- X {
- X /*
- X * No "home" string,
- X * but we can use "move(0,0)".
- X */
- X strcpy(sp, tgoto(sc_move, 0, 0));
- X sc_home = sp;
- X sp += strlen(sp) + 1;
- X }
- X }
- X
- X sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
- X if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
- X {
- X if (*sc_move == '\0')
- X {
- X cannot("move cursor to lower left of screen");
- X sc_lower_left = "\r";
- X } else
- X {
- X /*
- X * No "lower-left" string,
- X * but we can use "move(0,last-line)".
- X */
- X strcpy(sp, tgoto(sc_move, 0, sc_height-1));
- X sc_lower_left = sp;
- X sp += strlen(sp) + 1;
- X }
- X }
- X
- X /*
- X * To add a line at top of screen and scroll the display down,
- X * we use "al" (add line) or "sr" (scroll reverse).
- X */
- X if (dumb)
- X sc_addline = NULL;
- X else if ((sc_addline = tgetstr("al", &sp)) == NULL ||
- X *sc_addline == '\0')
- X sc_addline = tgetstr("sr", &sp);
- X
- X if (hard || sc_addline == NULL || *sc_addline == '\0')
- X {
- X cannot("scroll backwards");
- X sc_addline = "";
- X /* Force repaint on any backward movement */
- X back_scroll = 0;
- X }
- X
- X if (dumb || 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
- 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, putc);
- X}
- X
- X/*
- X * Deinitialize terminal
- X */
- X public void
- Xdeinit()
- X{
- X tputs(sc_deinit, sc_height, putc);
- X}
- X
- X/*
- X * Home cursor (move to upper left corner of screen).
- X */
- X public void
- Xhome()
- X{
- X tputs(sc_home, 1, putc);
- 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, putc);
- 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, putc);
- X}
- X
- X/*
- X * Ring the terminal bell.
- X */
- X public void
- Xbell()
- X{
- X if (quiet == VERY_QUIET)
- X vbell();
- X else
- X putc('\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, putc);
- X}
- X
- X/*
- X * Clear the screen.
- X */
- X public void
- Xclear()
- X{
- X tputs(sc_clear, sc_height, putc);
- 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, putc);
- X}
- X
- X/*
- X * Begin "standout" (bold, underline, or whatever).
- X */
- X public void
- Xso_enter()
- X{
- X tputs(sc_s_in, 1, putc);
- X}
- X
- X/*
- X * End "standout".
- X */
- X public void
- Xso_exit()
- X{
- X tputs(sc_s_out, 1, putc);
- 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, putc);
- X}
- X
- X/*
- X * End "underline".
- X */
- X public void
- Xul_exit()
- X{
- X tputs(sc_u_out, 1, putc);
- X}
- X
- X/*
- X * Begin "bold"
- X */
- X public void
- Xbo_enter()
- X{
- X tputs(sc_b_in, 1, putc);
- X}
- X
- X/*
- X * End "bold".
- X */
- X public void
- Xbo_exit()
- X{
- X tputs(sc_b_out, 1, putc);
- 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, putc);
- X putc(' ');
- X tputs(sc_backspace, 1, putc);
- X}
- X
- X/*
- X * Output a plain backspace, without erasing the previous char.
- X */
- X public void
- Xputbs()
- X{
- X tputs(sc_backspace, 1, putc);
- X}
- SHAR_EOF
- fi
- if test -f 'signal.c'
- then
- echo shar: "will not over-write existing file 'signal.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'signal.c'
- 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 * An exception is made if we are reading from the keyboard when the
- X * signal is received. Some operating systems will simply call the
- X * signal handler and NOT return from the read (with EINTR).
- X * To handle this case, we service the interrupt directly from
- X * the handler if we are reading from the keyboard.
- X */
- X
- X#include "less.h"
- X#include <signal.h>
- X#include <setjmp.h>
- X
- X/*
- X * The type of signal handler functions.
- X * Usually int, although it should be void.
- X */
- Xtypedef int HANDLER;
- X
- X/*
- X * "sigs" contains bits indicating signals which need to be processed.
- X */
- Xpublic int sigs;
- X#define S_INTERRUPT 01
- X#ifdef SIGTSTP
- X#define S_STOP 02
- X#endif
- X
- Xextern int reading;
- Xextern char *first_cmd;
- Xextern jmp_buf main_loop;
- X
- X/*
- X * Interrupt signal handler.
- X */
- X static HANDLER
- Xinterrupt()
- X{
- X SIGNAL(SIGINT, interrupt);
- X sigs |= S_INTERRUPT;
- X if (reading)
- X psignals();
- 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 psignals();
- X}
- X#endif
- X
- X/*
- X * Set up the signal handlers.
- X */
- X public void
- Xinit_signals()
- X{
- X (void) SIGNAL(SIGINT, interrupt);
- X#ifdef SIGTSTP
- X (void) SIGNAL(SIGTSTP, stop);
- X#endif
- X}
- X
- X/*
- X * Process any signals we have recieved.
- X * A received signal cause a bit to be set in "sigs".
- X */
- X public void
- Xpsignals()
- X{
- X register int tsignals;
- X
- X tsignals = sigs;
- X sigs = 0;
- X if (tsignals == 0)
- X return;
- X
- X dropout(); /* Discard any buffered output */
- X
- 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 flush();
- X raw_mode(0);
- X#ifdef SIGTTOU
- X SIGNAL(SIGTTOU, SIG_DFL);
- X#endif
- X SIGNAL(SIGTSTP, SIG_DFL);
- X#if SIGSETMASK
- X /*
- X * This system will not allow us to send a
- X * stop signal (SIGTSTP) to ourself
- X * while we are in the signal handler, like maybe now.
- X * (This can be the case if we are reading; see comment above.)
- X * So we ask the silly system for permission to do so.
- X */
- X sigsetmask(0);
- X#endif
- 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 first_cmd = "r";
- X longjmp(main_loop, 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 longjmp(main_loop, 1);
- X}
- X
- X/*
- X * Pass the specified command to a shell to be executed.
- X * Like plain "system()", but handles resetting terminal modes, etc.
- X */
- X public void
- Xlsystem(cmd)
- X char *cmd;
- X{
- X int inp;
- X
- X /*
- X * Print the command which is to be executed,
- X * unless the command starts with a "-".
- X */
- X if (cmd[0] == '-')
- X cmd++;
- X else
- X {
- X lower_left();
- X clear_eol();
- X puts("!");
- X puts(cmd);
- X puts("\n");
- X }
- X
- X /*
- X * De-initialize the terminal and take out of raw mode.
- X */
- X deinit();
- X flush();
- X raw_mode(0);
- X
- X /*
- X * Restore signals to their defaults.
- X */
- X SIGNAL(SIGINT, SIG_DFL);
- X#ifdef SIGTSTP
- X SIGNAL(SIGTSTP, SIG_DFL);
- X#endif
- X /*
- X * Force standard input to be the terminal, "/dev/tty".
- X */
- X inp = dup(0);
- X close(0);
- X open("/dev/tty", 0);
- X
- X /*
- X * Pass the command to the system to be executed.
- X */
- X system(cmd);
- X
- X /*
- X * Restore standard input, reset signals, raw mode, etc.
- X */
- X close(0);
- X dup(inp);
- X close(inp);
- X
- X init_signals();
- X raw_mode(1);
- X init();
- X}
- X
- X/*
- X * Expand a filename, substituting any environment variables, etc.
- X * The implementation of this is necessarily very operating system
- X * dependent. This implementation is unabashedly only for Unix systems.
- X */
- X#if GLOB
- X
- X#include <stdio.h>
- X
- X char *
- Xglob(filename)
- X char *filename;
- X{
- X FILE *f;
- X char *p;
- X int ch;
- X static char filebuf[128];
- X static char ECHO[] = "echo ";
- X
- X strcpy(filebuf, ECHO);
- X strtcpy(filebuf+sizeof(ECHO)-1, filename, sizeof(filebuf)-sizeof(ECHO));
- X if ((f = popen(filebuf, "r")) == NULL)
- X return (filename);
- X for (p = filebuf; p < &filebuf[sizeof(filebuf)-1]; p++)
- X {
- X if ((ch = getc(f)) == '\n' || ch == EOF)
- X break;
- X *p = ch;
- X }
- X *p = '\0';
- X pclose(f);
- X return (filebuf);
- X}
- X
- X#else
- X
- X char *
- Xglob(filename)
- X char *filename;
- X{
- X return (filename);
- X}
- X
- X#endif
- SHAR_EOF
- fi
- if test -f 'ttyin.c'
- then
- echo shar: "will not over-write existing file 'ttyin.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'ttyin.c'
- X/*
- X * Routines dealing with getting input from the keyboard (i.e. from the user).
- X */
- X
- X#include "less.h"
- X
- X/*
- X * The boolean "reading" is set true or false according to whether
- X * we are currently reading from the keyboard.
- X * This information is used by the signal handling stuff in signal.c.
- X * {{ There are probably some race conditions here
- X * involving the variable "reading". }}
- X */
- Xpublic int reading;
- X
- Xstatic int tty;
- X
- X/*
- X * Open keyboard for input.
- X * (Just use file descriptor 2.)
- X */
- X public void
- Xopen_getc()
- X{
- X tty = 2;
- X}
- X
- X/*
- X * Get a character from the keyboard.
- X */
- X public int
- Xgetc()
- X{
- X char c;
- X int result;
- X
- X reading = 1;
- X do
- X {
- X flush();
- X result = read(tty, &c, 1);
- X } while (result != 1);
- X reading = 0;
- X return (c & 0177);
- X}
- SHAR_EOF
- fi
- if test -f 'version.c'
- then
- echo shar: "will not over-write existing file 'version.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'version.c'
- X/*
- X * less
- X * Copyright (c) 1984,1985 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 *
- 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 * 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 * 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 * -----------------------------------------------------------------
- X */
- X
- Xchar version[] = "@(#) less version 61";
- SHAR_EOF
- fi
- cd ..
- exit 0
- # End of shell archive
-