more is less.
less is more. QED.
This commit is contained in:
parent
9b6032417d
commit
a6fe8f7e38
@ -1,18 +0,0 @@
|
||||
# from: @(#)Makefile 5.6 (Berkeley) 3/12/91
|
||||
# $Id: Makefile,v 1.6 1994/04/16 08:14:50 andrew Exp $
|
||||
|
||||
PROG= more
|
||||
CFLAGS+=-I${.CURDIR} -DREGEX -DTERMIOS
|
||||
SRCS= ch.c command.c decode.c filename.c help.c input.c line.c \
|
||||
linenum.c main.c option.c os.c output.c position.c prim.c \
|
||||
screen.c signal.c tags.c ttyin.c
|
||||
LDADD+= -ltermcap
|
||||
DPADD+= ${LIBTERM}
|
||||
MLINKS= more.1 page.1
|
||||
LINKS= ${BINDIR}/more ${BINDIR}/page
|
||||
|
||||
beforeinstall:
|
||||
install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/more.help \
|
||||
${DESTDIR}/usr/share/misc
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,453 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)ch.c 5.11 (Berkeley) 6/21/92"; */
|
||||
static char *rcsid = "$Id: ch.c,v 1.3 1994/04/06 17:50:39 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Low level character input from the input file.
|
||||
* We use these special purpose routines which optimize moving
|
||||
* both forward and backward from the current read pointer.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <less.h>
|
||||
|
||||
int file = -1; /* File descriptor of the input file */
|
||||
|
||||
/*
|
||||
* Pool of buffers holding the most recently used blocks of the input file.
|
||||
*/
|
||||
struct buf {
|
||||
struct buf *next, *prev;
|
||||
long block;
|
||||
int datasize;
|
||||
char data[BUFSIZ];
|
||||
};
|
||||
int nbufs;
|
||||
|
||||
/*
|
||||
* The buffer pool is kept as a doubly-linked circular list, in order from
|
||||
* most- to least-recently used. The circular list is anchored by buf_anchor.
|
||||
*/
|
||||
#define END_OF_CHAIN ((struct buf *)&buf_anchor)
|
||||
#define buf_head buf_anchor.next
|
||||
#define buf_tail buf_anchor.prev
|
||||
|
||||
static struct {
|
||||
struct buf *next, *prev;
|
||||
} buf_anchor = { END_OF_CHAIN, END_OF_CHAIN };
|
||||
|
||||
extern int ispipe, cbufs, sigs;
|
||||
|
||||
/*
|
||||
* Current position in file.
|
||||
* Stored as a block number and an offset into the block.
|
||||
*/
|
||||
static long ch_block;
|
||||
static int ch_offset;
|
||||
|
||||
/* Length of file, needed if input is a pipe. */
|
||||
static off_t ch_fsize;
|
||||
|
||||
/* Number of bytes read, if input is standard input (a pipe). */
|
||||
static off_t last_piped_pos;
|
||||
|
||||
/*
|
||||
* Get the character pointed to by the read pointer. ch_get() is a macro
|
||||
* which is more efficient to call than fch_get (the function), in the usual
|
||||
* case that the block desired is at the head of the chain.
|
||||
*/
|
||||
#define ch_get() \
|
||||
((buf_head->block == ch_block && \
|
||||
ch_offset < buf_head->datasize) ? \
|
||||
buf_head->data[ch_offset] : fch_get())
|
||||
|
||||
static
|
||||
fch_get()
|
||||
{
|
||||
extern int bs_mode;
|
||||
register struct buf *bp;
|
||||
register int n, ch;
|
||||
register char *p, *t;
|
||||
off_t pos;
|
||||
|
||||
/* look for a buffer holding the desired block. */
|
||||
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
|
||||
if (bp->block == ch_block) {
|
||||
if (ch_offset >= bp->datasize)
|
||||
/*
|
||||
* Need more data in this buffer.
|
||||
*/
|
||||
goto read_more;
|
||||
/*
|
||||
* On a pipe, we don't sort the buffers LRU
|
||||
* because this can cause gaps in the buffers.
|
||||
* For example, suppose we've got 12 1K buffers,
|
||||
* and a 15K input stream. If we read the first 12K
|
||||
* sequentially, then jump to line 1, then jump to
|
||||
* the end, the buffers have blocks 0,4,5,6,..,14.
|
||||
* If we then jump to line 1 again and try to
|
||||
* read sequentially, we're out of luck when we
|
||||
* get to block 1 (we'd get the "pipe error" below).
|
||||
* To avoid this, we only sort buffers on a pipe
|
||||
* when we actually READ the data, not when we
|
||||
* find it already buffered.
|
||||
*/
|
||||
if (ispipe)
|
||||
return(bp->data[ch_offset]);
|
||||
goto found;
|
||||
}
|
||||
/*
|
||||
* Block is not in a buffer. Take the least recently used buffer
|
||||
* and read the desired block into it. If the LRU buffer has data
|
||||
* in it, and input is a pipe, then try to allocate a new buffer first.
|
||||
*/
|
||||
if (ispipe && buf_tail->block != (long)(-1))
|
||||
(void)ch_addbuf(1);
|
||||
bp = buf_tail;
|
||||
bp->block = ch_block;
|
||||
bp->datasize = 0;
|
||||
|
||||
read_more:
|
||||
pos = (ch_block * BUFSIZ) + bp->datasize;
|
||||
if (ispipe) {
|
||||
/*
|
||||
* The data requested should be immediately after
|
||||
* the last data read from the pipe.
|
||||
*/
|
||||
if (pos != last_piped_pos) {
|
||||
error("pipe error");
|
||||
quit();
|
||||
}
|
||||
} else
|
||||
(void)lseek(file, pos, L_SET);
|
||||
|
||||
/*
|
||||
* Read the block.
|
||||
* If we read less than a full block, we just return the
|
||||
* partial block and pick up the rest next time.
|
||||
*/
|
||||
n = iread(file, &bp->data[bp->datasize], BUFSIZ - bp->datasize);
|
||||
if (n == READ_INTR)
|
||||
return (EOI);
|
||||
if (n < 0) {
|
||||
error("read error");
|
||||
quit();
|
||||
}
|
||||
if (ispipe)
|
||||
last_piped_pos += n;
|
||||
|
||||
p = &bp->data[bp->datasize];
|
||||
bp->datasize += n;
|
||||
|
||||
/*
|
||||
* Set an EOI marker in the buffered data itself. Then ensure the
|
||||
* data is "clean": there are no extra EOI chars in the data and
|
||||
* that the "meta" bit (the 0200 bit) is reset in each char;
|
||||
* also translate \r\n sequences to \n if -u flag not set.
|
||||
*/
|
||||
if (n == 0) {
|
||||
ch_fsize = pos;
|
||||
bp->data[bp->datasize++] = EOI;
|
||||
}
|
||||
|
||||
if (bs_mode) {
|
||||
for (p = &bp->data[bp->datasize]; --n >= 0;) {
|
||||
*--p &= 0177;
|
||||
if (*p == EOI)
|
||||
*p = 0200;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (t = p; --n >= 0; ++p) {
|
||||
ch = *p & 0177;
|
||||
if (ch == '\r' && n && (p[1] & 0177) == '\n') {
|
||||
++p;
|
||||
*t++ = '\n';
|
||||
}
|
||||
else
|
||||
*t++ = (ch == EOI) ? 0200 : ch;
|
||||
}
|
||||
if (p != t) {
|
||||
bp->datasize -= p - t;
|
||||
if (ispipe)
|
||||
last_piped_pos -= p - t;
|
||||
}
|
||||
}
|
||||
|
||||
found:
|
||||
if (buf_head != bp) {
|
||||
/*
|
||||
* Move the buffer to the head of the buffer chain.
|
||||
* This orders the buffer chain, most- to least-recently used.
|
||||
*/
|
||||
bp->next->prev = bp->prev;
|
||||
bp->prev->next = bp->next;
|
||||
|
||||
bp->next = buf_head;
|
||||
bp->prev = END_OF_CHAIN;
|
||||
buf_head->prev = bp;
|
||||
buf_head = bp;
|
||||
}
|
||||
|
||||
if (ch_offset >= bp->datasize)
|
||||
/*
|
||||
* After all that, we still don't have enough data.
|
||||
* Go back and try again.
|
||||
*/
|
||||
goto read_more;
|
||||
|
||||
return(bp->data[ch_offset]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if a specific block is currently in one of the buffers.
|
||||
*/
|
||||
static
|
||||
buffered(block)
|
||||
long block;
|
||||
{
|
||||
register struct buf *bp;
|
||||
|
||||
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
|
||||
if (bp->block == block)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Seek to a specified position in the file.
|
||||
* Return 0 if successful, non-zero if can't seek there.
|
||||
*/
|
||||
ch_seek(pos)
|
||||
register off_t pos;
|
||||
{
|
||||
long new_block;
|
||||
|
||||
new_block = pos / BUFSIZ;
|
||||
if (!ispipe || pos == last_piped_pos || buffered(new_block)) {
|
||||
/*
|
||||
* Set read pointer.
|
||||
*/
|
||||
ch_block = new_block;
|
||||
ch_offset = pos % BUFSIZ;
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Seek to the end of the file.
|
||||
*/
|
||||
ch_end_seek()
|
||||
{
|
||||
off_t ch_length();
|
||||
|
||||
if (!ispipe)
|
||||
return(ch_seek(ch_length()));
|
||||
|
||||
/*
|
||||
* Do it the slow way: read till end of data.
|
||||
*/
|
||||
while (ch_forw_get() != EOI)
|
||||
if (sigs)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Seek to the beginning of the file, or as close to it as we can get.
|
||||
* We may not be able to seek there if input is a pipe and the
|
||||
* beginning of the pipe is no longer buffered.
|
||||
*/
|
||||
ch_beg_seek()
|
||||
{
|
||||
register struct buf *bp, *firstbp;
|
||||
|
||||
/*
|
||||
* Try a plain ch_seek first.
|
||||
*/
|
||||
if (ch_seek((off_t)0) == 0)
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* Can't get to position 0.
|
||||
* Look thru the buffers for the one closest to position 0.
|
||||
*/
|
||||
firstbp = bp = buf_head;
|
||||
if (bp == END_OF_CHAIN)
|
||||
return(1);
|
||||
while ((bp = bp->next) != END_OF_CHAIN)
|
||||
if (bp->block < firstbp->block)
|
||||
firstbp = bp;
|
||||
ch_block = firstbp->block;
|
||||
ch_offset = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the length of the file, if known.
|
||||
*/
|
||||
off_t
|
||||
ch_length()
|
||||
{
|
||||
if (ispipe)
|
||||
return(ch_fsize);
|
||||
return((off_t)(lseek(file, (off_t)0, L_XTND)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current position in the file.
|
||||
*/
|
||||
off_t
|
||||
ch_tell()
|
||||
{
|
||||
return(ch_block * BUFSIZ + ch_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current char and post-increment the read pointer.
|
||||
*/
|
||||
ch_forw_get()
|
||||
{
|
||||
register int c;
|
||||
|
||||
c = ch_get();
|
||||
if (c != EOI && ++ch_offset >= BUFSIZ) {
|
||||
ch_offset = 0;
|
||||
++ch_block;
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre-decrement the read pointer and get the new current char.
|
||||
*/
|
||||
ch_back_get()
|
||||
{
|
||||
if (--ch_offset < 0) {
|
||||
if (ch_block <= 0 || (ispipe && !buffered(ch_block-1))) {
|
||||
ch_offset = 0;
|
||||
return(EOI);
|
||||
}
|
||||
ch_offset = BUFSIZ - 1;
|
||||
ch_block--;
|
||||
}
|
||||
return(ch_get());
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate buffers.
|
||||
* Caller wants us to have a total of at least want_nbufs buffers.
|
||||
* keep==1 means keep the data in the current buffers;
|
||||
* otherwise discard the old data.
|
||||
*/
|
||||
ch_init(want_nbufs, keep)
|
||||
int want_nbufs;
|
||||
int keep;
|
||||
{
|
||||
register struct buf *bp;
|
||||
char message[80];
|
||||
|
||||
cbufs = nbufs;
|
||||
if (nbufs < want_nbufs && ch_addbuf(want_nbufs - nbufs)) {
|
||||
/*
|
||||
* Cannot allocate enough buffers.
|
||||
* If we don't have ANY, then quit.
|
||||
* Otherwise, just report the error and return.
|
||||
*/
|
||||
(void)sprintf(message, "cannot allocate %d buffers",
|
||||
want_nbufs - nbufs);
|
||||
error(message);
|
||||
if (nbufs == 0)
|
||||
quit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keep)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We don't want to keep the old data,
|
||||
* so initialize all the buffers now.
|
||||
*/
|
||||
for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next)
|
||||
bp->block = (long)(-1);
|
||||
last_piped_pos = (off_t)0;
|
||||
ch_fsize = NULL_POSITION;
|
||||
(void)ch_seek((off_t)0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate some new buffers.
|
||||
* The buffers are added to the tail of the buffer chain.
|
||||
*/
|
||||
ch_addbuf(nnew)
|
||||
int nnew;
|
||||
{
|
||||
register struct buf *bp;
|
||||
register struct buf *newbufs;
|
||||
char *calloc();
|
||||
|
||||
/*
|
||||
* We don't have enough buffers.
|
||||
* Allocate some new ones.
|
||||
*/
|
||||
newbufs = (struct buf *)calloc((u_int)nnew, sizeof(struct buf));
|
||||
if (newbufs == NULL)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* Initialize the new buffers and link them together.
|
||||
* Link them all onto the tail of the buffer list.
|
||||
*/
|
||||
nbufs += nnew;
|
||||
cbufs = nbufs;
|
||||
for (bp = &newbufs[0]; bp < &newbufs[nnew]; bp++) {
|
||||
bp->next = bp + 1;
|
||||
bp->prev = bp - 1;
|
||||
bp->block = (long)(-1);
|
||||
}
|
||||
newbufs[nnew-1].next = END_OF_CHAIN;
|
||||
newbufs[0].prev = buf_tail;
|
||||
buf_tail->next = &newbufs[0];
|
||||
buf_tail = &newbufs[nnew-1];
|
||||
return(0);
|
||||
}
|
@ -1,692 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)command.c 5.22 (Berkeley) 6/21/92"; */
|
||||
static char *rcsid = "$Id: command.c,v 1.6 1995/08/06 09:22:30 ghudson Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <less.h>
|
||||
#include "pathnames.h"
|
||||
|
||||
#define NO_MCA 0
|
||||
#define MCA_DONE 1
|
||||
#define MCA_MORE 2
|
||||
|
||||
extern int erase_char, kill_char, werase_char;
|
||||
extern int ispipe;
|
||||
extern int sigs;
|
||||
extern int quit_at_eof;
|
||||
extern int hit_eof;
|
||||
extern int sc_width;
|
||||
extern int sc_height;
|
||||
extern int sc_window;
|
||||
extern int curr_ac;
|
||||
extern int ac;
|
||||
extern int quitting;
|
||||
extern int scroll;
|
||||
extern int screen_trashed; /* The screen has been overwritten */
|
||||
extern int novice;
|
||||
|
||||
static char cmdbuf[120]; /* Buffer for holding a multi-char command */
|
||||
static char *cp; /* Pointer into cmdbuf */
|
||||
static int cmd_col; /* Current column of the multi-char command */
|
||||
static int longprompt; /* if stat command instead of prompt */
|
||||
static int helpprompt; /* If help directions instead of prompt */
|
||||
static int mca; /* The multicharacter command (action) */
|
||||
static int last_mca; /* The previous mca */
|
||||
static int number; /* The number typed by the user */
|
||||
static char *shellcmd = NULL; /* Pointer to a shell command */
|
||||
static int wsearch; /* Search for matches (1) or non-matches (0) */
|
||||
|
||||
#define CMD_RESET cp = cmdbuf /* reset command buffer to empty */
|
||||
#define CMD_EXEC lower_left(); flush()
|
||||
|
||||
/* backspace in command buffer. */
|
||||
static
|
||||
cmd_erase()
|
||||
{
|
||||
/*
|
||||
* backspace past beginning of the string: this usually means
|
||||
* abort the command.
|
||||
*/
|
||||
if (cp == cmdbuf)
|
||||
return(1);
|
||||
|
||||
/* erase an extra character, for the carat. */
|
||||
if (CONTROL_CHAR(*--cp)) {
|
||||
backspace();
|
||||
--cmd_col;
|
||||
}
|
||||
|
||||
backspace();
|
||||
--cmd_col;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* set up the display to start a new multi-character command. */
|
||||
start_mca(action, prompt)
|
||||
int action;
|
||||
char *prompt;
|
||||
{
|
||||
lower_left();
|
||||
clear_eol();
|
||||
putstr(prompt);
|
||||
cmd_col = strlen(prompt);
|
||||
mca = action;
|
||||
}
|
||||
|
||||
/*
|
||||
* process a single character of a multi-character command, such as
|
||||
* a number, or the pattern of a search command.
|
||||
*/
|
||||
static
|
||||
cmd_char(c)
|
||||
int c;
|
||||
{
|
||||
if (c == erase_char)
|
||||
return(cmd_erase());
|
||||
/* in this order, in case werase == erase_char */
|
||||
if (c == werase_char) {
|
||||
if (cp > cmdbuf) {
|
||||
while (isspace(cp[-1]) && !cmd_erase());
|
||||
while (!isspace(cp[-1]) && !cmd_erase());
|
||||
while (isspace(cp[-1]) && !cmd_erase());
|
||||
}
|
||||
return(cp == cmdbuf);
|
||||
}
|
||||
if (c == kill_char) {
|
||||
while (!cmd_erase());
|
||||
return(1);
|
||||
}
|
||||
/*
|
||||
* No room in the command buffer, or no room on the screen;
|
||||
* {{ Could get fancy here; maybe shift the displayed line
|
||||
* and make room for more chars, like ksh. }}
|
||||
*/
|
||||
if (cp >= &cmdbuf[sizeof(cmdbuf)-1] || cmd_col >= sc_width-3)
|
||||
bell();
|
||||
else {
|
||||
*cp++ = c;
|
||||
if (CONTROL_CHAR(c)) {
|
||||
putchr('^');
|
||||
cmd_col++;
|
||||
c = CARAT_CHAR(c);
|
||||
}
|
||||
putchr(c);
|
||||
cmd_col++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
off_t position();
|
||||
|
||||
prompt()
|
||||
{
|
||||
extern int linenums, short_file;
|
||||
extern char *current_name, *firstsearch, *next_name;
|
||||
off_t len, pos, ch_length(), forw_line();
|
||||
char pbuf[40];
|
||||
|
||||
/*
|
||||
* if nothing is displayed yet, display starting from line 1;
|
||||
* if search string provided, go there instead.
|
||||
*/
|
||||
if (position(TOP) == NULL_POSITION) {
|
||||
if (forw_line((off_t)0) == NULL_POSITION)
|
||||
return(0);
|
||||
if (!firstsearch || !search(1, firstsearch, 1, 1))
|
||||
jump_back(1);
|
||||
}
|
||||
else if (screen_trashed)
|
||||
repaint();
|
||||
|
||||
/* if no -e flag and we've hit EOF on the last file, quit. */
|
||||
if ((!quit_at_eof || short_file) && hit_eof && curr_ac + 1 >= ac)
|
||||
quit();
|
||||
|
||||
/* select the proper prompt and display it. */
|
||||
lower_left();
|
||||
clear_eol();
|
||||
if (longprompt) {
|
||||
so_enter();
|
||||
putstr(current_name);
|
||||
putstr(":");
|
||||
if (!ispipe) {
|
||||
(void)sprintf(pbuf, " file %d/%d", curr_ac + 1, ac);
|
||||
putstr(pbuf);
|
||||
}
|
||||
if (linenums) {
|
||||
(void)sprintf(pbuf, " line %d", currline(BOTTOM));
|
||||
putstr(pbuf);
|
||||
}
|
||||
if ((pos = position(BOTTOM)) != NULL_POSITION) {
|
||||
(void)sprintf(pbuf, " byte %qd", pos);
|
||||
putstr(pbuf);
|
||||
if (!ispipe && (len = ch_length())) {
|
||||
(void)sprintf(pbuf, "/%qd pct %qd%%",
|
||||
len, ((100 * pos) / len));
|
||||
putstr(pbuf);
|
||||
}
|
||||
}
|
||||
so_exit();
|
||||
longprompt = 0;
|
||||
}
|
||||
else if (helpprompt) {
|
||||
so_enter();
|
||||
putstr("[Press 'h' for instructions.]");
|
||||
so_exit();
|
||||
helpprompt = 0;
|
||||
}
|
||||
else {
|
||||
so_enter();
|
||||
putstr(current_name);
|
||||
if (hit_eof)
|
||||
if (next_name) {
|
||||
putstr(": END (next file: ");
|
||||
putstr(next_name);
|
||||
putstr(")");
|
||||
}
|
||||
else
|
||||
putstr(": END");
|
||||
else if (!ispipe &&
|
||||
(pos = position(BOTTOM)) != NULL_POSITION &&
|
||||
(len = ch_length())) {
|
||||
(void)sprintf(pbuf, " (%qd%%)", ((100 * pos) / len));
|
||||
putstr(pbuf);
|
||||
}
|
||||
if (novice)
|
||||
putstr(" [Press space to continue, 'q' to quit.]");
|
||||
so_exit();
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* get command character. */
|
||||
static
|
||||
getcc()
|
||||
{
|
||||
extern int cmdstack;
|
||||
int ch;
|
||||
|
||||
/* left over from error() routine. */
|
||||
if (cmdstack) {
|
||||
ch = cmdstack;
|
||||
cmdstack = NULL;
|
||||
return(ch);
|
||||
}
|
||||
if (cp > cmdbuf && position(TOP) == NULL_POSITION) {
|
||||
/*
|
||||
* Command is incomplete, so try to complete it.
|
||||
* There are only two cases:
|
||||
* 1. We have "/string" but no newline. Add the \n.
|
||||
* 2. We have a number but no command. Treat as #g.
|
||||
* (This is all pretty hokey.)
|
||||
*/
|
||||
if (mca != A_DIGIT)
|
||||
/* Not a number; must be search string */
|
||||
return('\n');
|
||||
else
|
||||
/* A number; append a 'g' */
|
||||
return('g');
|
||||
}
|
||||
return(getchr());
|
||||
}
|
||||
|
||||
/* execute a multicharacter command. */
|
||||
static
|
||||
exec_mca()
|
||||
{
|
||||
extern int file;
|
||||
extern char *tagfile;
|
||||
register char *p;
|
||||
char *glob(), *fexpand();
|
||||
|
||||
*cp = '\0';
|
||||
CMD_EXEC;
|
||||
switch (mca) {
|
||||
case A_F_SEARCH:
|
||||
(void)search(1, cmdbuf, number, wsearch);
|
||||
break;
|
||||
case A_B_SEARCH:
|
||||
(void)search(0, cmdbuf, number, wsearch);
|
||||
break;
|
||||
case A_EXAMINE:
|
||||
for (p = cmdbuf; isspace(*p); ++p);
|
||||
(void)edit(glob(p));
|
||||
break;
|
||||
case A_SHELL:
|
||||
/*
|
||||
* Copy cmdbuf to shellcmd,
|
||||
* expanding any special characters ("%" or "#"
|
||||
* or an initial !).
|
||||
*/
|
||||
if ((p = fexpand(cmdbuf, shellcmd)) == NULL)
|
||||
break;
|
||||
else if (shellcmd != NULL)
|
||||
free(shellcmd);
|
||||
lsystem(shellcmd = p);
|
||||
error("!done");
|
||||
break;
|
||||
case A_TAGFILE:
|
||||
for (p = cmdbuf; isspace(*p); ++p);
|
||||
findtag(p);
|
||||
if (tagfile == NULL)
|
||||
break;
|
||||
if (edit(tagfile))
|
||||
(void)tagsearch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* add a character to a multi-character command. */
|
||||
static
|
||||
mca_char(c)
|
||||
int c;
|
||||
{
|
||||
switch (mca) {
|
||||
case 0: /* not in a multicharacter command. */
|
||||
case A_PREFIX: /* in the prefix of a command. */
|
||||
return(NO_MCA);
|
||||
case A_DIGIT:
|
||||
/*
|
||||
* Entering digits of a number.
|
||||
* Terminated by a non-digit.
|
||||
*/
|
||||
if (!isascii(c) || !isdigit(c) &&
|
||||
c != erase_char && c != kill_char && c != werase_char) {
|
||||
/*
|
||||
* Not part of the number.
|
||||
* Treat as a normal command character.
|
||||
*/
|
||||
*cp = '\0';
|
||||
number = atoi(cmdbuf);
|
||||
CMD_RESET;
|
||||
mca = 0;
|
||||
return(NO_MCA);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any other multicharacter command
|
||||
* is terminated by a newline.
|
||||
*/
|
||||
if (c == '\n' || c == '\r') {
|
||||
exec_mca();
|
||||
return(MCA_DONE);
|
||||
}
|
||||
|
||||
/* append the char to the command buffer. */
|
||||
if (cmd_char(c))
|
||||
return(MCA_DONE);
|
||||
|
||||
return(MCA_MORE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main command processor.
|
||||
* Accept and execute commands until a quit command, then return.
|
||||
*/
|
||||
commands()
|
||||
{
|
||||
register int c;
|
||||
register int action;
|
||||
|
||||
last_mca = 0;
|
||||
scroll = (sc_height + 1) / 2;
|
||||
|
||||
for (;;) {
|
||||
mca = 0;
|
||||
number = 0;
|
||||
|
||||
/*
|
||||
* See if any signals need processing.
|
||||
*/
|
||||
if (sigs) {
|
||||
psignals();
|
||||
if (quitting)
|
||||
quit();
|
||||
}
|
||||
/*
|
||||
* Display prompt and accept a character.
|
||||
*/
|
||||
CMD_RESET;
|
||||
if (!prompt()) {
|
||||
next_file(1);
|
||||
continue;
|
||||
}
|
||||
noprefix();
|
||||
c = getcc();
|
||||
|
||||
again: if (sigs)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we are in a multicharacter command, call mca_char.
|
||||
* Otherwise we call cmd_decode to determine the
|
||||
* action to be performed.
|
||||
*/
|
||||
if (mca)
|
||||
switch (mca_char(c)) {
|
||||
case MCA_MORE:
|
||||
/*
|
||||
* Need another character.
|
||||
*/
|
||||
c = getcc();
|
||||
goto again;
|
||||
case MCA_DONE:
|
||||
/*
|
||||
* Command has been handled by mca_char.
|
||||
* Start clean with a prompt.
|
||||
*/
|
||||
continue;
|
||||
case NO_MCA:
|
||||
/*
|
||||
* Not a multi-char command
|
||||
* (at least, not anymore).
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* decode the command character and decide what to do. */
|
||||
switch (action = cmd_decode(c)) {
|
||||
case A_DIGIT: /* first digit of a number */
|
||||
start_mca(A_DIGIT, ":");
|
||||
goto again;
|
||||
case A_F_SCREEN: /* forward one screen */
|
||||
CMD_EXEC;
|
||||
if (number <= 0 && (number = sc_window) <= 0)
|
||||
number = sc_height - 1;
|
||||
forward(number, 1);
|
||||
break;
|
||||
case A_B_SCREEN: /* backward one screen */
|
||||
CMD_EXEC;
|
||||
if (number <= 0 && (number = sc_window) <= 0)
|
||||
number = sc_height - 1;
|
||||
backward(number, 1);
|
||||
break;
|
||||
case A_F_LINE: /* forward N (default 1) line */
|
||||
CMD_EXEC;
|
||||
forward(number <= 0 ? 1 : number, 0);
|
||||
break;
|
||||
case A_B_LINE: /* backward N (default 1) line */
|
||||
CMD_EXEC;
|
||||
backward(number <= 0 ? 1 : number, 0);
|
||||
break;
|
||||
case A_F_SCROLL: /* forward N lines */
|
||||
CMD_EXEC;
|
||||
if (number > 0)
|
||||
scroll = number;
|
||||
forward(scroll, 0);
|
||||
break;
|
||||
case A_B_SCROLL: /* backward N lines */
|
||||
CMD_EXEC;
|
||||
if (number > 0)
|
||||
scroll = number;
|
||||
backward(scroll, 0);
|
||||
break;
|
||||
case A_FREPAINT: /* flush buffers and repaint */
|
||||
if (!ispipe) {
|
||||
ch_init(0, 0);
|
||||
clr_linenum();
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case A_REPAINT: /* repaint the screen */
|
||||
CMD_EXEC;
|
||||
repaint();
|
||||
break;
|
||||
case A_GOLINE: /* go to line N, default 1 */
|
||||
CMD_EXEC;
|
||||
if (number <= 0)
|
||||
number = 1;
|
||||
jump_back(number);
|
||||
break;
|
||||
case A_PERCENT: /* go to percent of file */
|
||||
CMD_EXEC;
|
||||
if (number < 0)
|
||||
number = 0;
|
||||
else if (number > 100)
|
||||
number = 100;
|
||||
jump_percent(number);
|
||||
break;
|
||||
case A_GOEND: /* go to line N, default end */
|
||||
CMD_EXEC;
|
||||
if (number <= 0)
|
||||
jump_forw();
|
||||
else
|
||||
jump_back(number);
|
||||
break;
|
||||
case A_STAT: /* print file name, etc. */
|
||||
longprompt = 1;
|
||||
continue;
|
||||
case A_QUIT: /* exit */
|
||||
quit();
|
||||
case A_F_SEARCH: /* search for a pattern */
|
||||
case A_B_SEARCH:
|
||||
if (number <= 0)
|
||||
number = 1;
|
||||
start_mca(action, (action==A_F_SEARCH) ? "/" : "?");
|
||||
last_mca = mca;
|
||||
wsearch = 1;
|
||||
c = getcc();
|
||||
if (c == '!') {
|
||||
/*
|
||||
* Invert the sense of the search; set wsearch
|
||||
* to 0 and get a new character for the start
|
||||
* of the pattern.
|
||||
*/
|
||||
start_mca(action,
|
||||
(action == A_F_SEARCH) ? "!/" : "!?");
|
||||
wsearch = 0;
|
||||
c = getcc();
|
||||
}
|
||||
goto again;
|
||||
case A_AGAIN_SEARCH: /* repeat previous search */
|
||||
if (number <= 0)
|
||||
number = 1;
|
||||
if (wsearch)
|
||||
start_mca(last_mca,
|
||||
(last_mca == A_F_SEARCH) ? "/" : "?");
|
||||
else
|
||||
start_mca(last_mca,
|
||||
(last_mca == A_F_SEARCH) ? "!/" : "!?");
|
||||
CMD_EXEC;
|
||||
(void)search(mca == A_F_SEARCH, (char *)NULL,
|
||||
number, wsearch);
|
||||
break;
|
||||
case A_HELP: /* help */
|
||||
lower_left();
|
||||
clear_eol();
|
||||
putstr("help");
|
||||
CMD_EXEC;
|
||||
help();
|
||||
break;
|
||||
case A_TAGFILE: /* tag a new file */
|
||||
CMD_RESET;
|
||||
start_mca(A_TAGFILE, "Tag: ");
|
||||
c = getcc();
|
||||
goto again;
|
||||
case A_FILE_LIST: /* show list of file names */
|
||||
CMD_EXEC;
|
||||
showlist();
|
||||
repaint();
|
||||
break;
|
||||
case A_EXAMINE: /* edit a new file */
|
||||
CMD_RESET;
|
||||
start_mca(A_EXAMINE, "Examine: ");
|
||||
c = getcc();
|
||||
goto again;
|
||||
case A_VISUAL: /* invoke the editor */
|
||||
if (ispipe) {
|
||||
error("Cannot edit standard input");
|
||||
break;
|
||||
}
|
||||
CMD_EXEC;
|
||||
editfile();
|
||||
ch_init(0, 0);
|
||||
clr_linenum();
|
||||
break;
|
||||
case A_NEXT_FILE: /* examine next file */
|
||||
if (number <= 0)
|
||||
number = 1;
|
||||
next_file(number);
|
||||
break;
|
||||
case A_PREV_FILE: /* examine previous file */
|
||||
if (number <= 0)
|
||||
number = 1;
|
||||
prev_file(number);
|
||||
break;
|
||||
case A_SETMARK: /* set a mark */
|
||||
lower_left();
|
||||
clear_eol();
|
||||
start_mca(A_SETMARK, "mark: ");
|
||||
c = getcc();
|
||||
if (c == erase_char || c == kill_char)
|
||||
break;
|
||||
setmark(c);
|
||||
break;
|
||||
case A_GOMARK: /* go to mark */
|
||||
lower_left();
|
||||
clear_eol();
|
||||
start_mca(A_GOMARK, "goto mark: ");
|
||||
c = getcc();
|
||||
if (c == erase_char || c == kill_char)
|
||||
break;
|
||||
gomark(c);
|
||||
break;
|
||||
case A_SHELL:
|
||||
/*
|
||||
* Shell escape.
|
||||
*/
|
||||
start_mca(A_SHELL, "!");
|
||||
c = getcc();
|
||||
goto again;
|
||||
case A_PREFIX:
|
||||
/*
|
||||
* The command is incomplete (more chars are needed).
|
||||
* Display the current char so the user knows what's
|
||||
* going on and get another character.
|
||||
*/
|
||||
if (mca != A_PREFIX)
|
||||
start_mca(A_PREFIX, "");
|
||||
if (CONTROL_CHAR(c)) {
|
||||
putchr('^');
|
||||
c = CARAT_CHAR(c);
|
||||
}
|
||||
putchr(c);
|
||||
c = getcc();
|
||||
goto again;
|
||||
default:
|
||||
if (novice)
|
||||
helpprompt = 1;
|
||||
else
|
||||
bell();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editfile()
|
||||
{
|
||||
extern char *current_file;
|
||||
static int dolinenumber;
|
||||
static char *editor;
|
||||
int c;
|
||||
char buf[MAXPATHLEN * 2 + 20], *getenv();
|
||||
|
||||
if (editor == NULL) {
|
||||
editor = getenv("EDITOR");
|
||||
/* pass the line number to vi */
|
||||
if (editor == NULL || *editor == '\0') {
|
||||
editor = _PATH_VI;
|
||||
dolinenumber = 1;
|
||||
}
|
||||
else
|
||||
dolinenumber = 0;
|
||||
}
|
||||
if (dolinenumber && (c = currline(MIDDLE)))
|
||||
(void)sprintf(buf, "%s +%d %s", editor, c, current_file);
|
||||
else
|
||||
(void)sprintf(buf, "%s %s", editor, current_file);
|
||||
lsystem(buf);
|
||||
}
|
||||
|
||||
showlist()
|
||||
{
|
||||
extern int sc_width;
|
||||
extern char **av;
|
||||
register int indx, width;
|
||||
int len;
|
||||
char *p;
|
||||
|
||||
if (ac <= 0) {
|
||||
error("No files provided as arguments.");
|
||||
return;
|
||||
}
|
||||
for (width = indx = 0; indx < ac;) {
|
||||
p = strcmp(av[indx], "-") ? av[indx] : "stdin";
|
||||
len = strlen(p) + 1;
|
||||
if (curr_ac == indx)
|
||||
len += 2;
|
||||
if (width + len + 1 >= sc_width) {
|
||||
if (!width) {
|
||||
if (curr_ac == indx)
|
||||
putchr('[');
|
||||
putstr(p);
|
||||
if (curr_ac == indx)
|
||||
putchr(']');
|
||||
++indx;
|
||||
}
|
||||
width = 0;
|
||||
putchr('\n');
|
||||
continue;
|
||||
}
|
||||
if (width)
|
||||
putchr(' ');
|
||||
if (curr_ac == indx)
|
||||
putchr('[');
|
||||
putstr(p);
|
||||
if (curr_ac == indx)
|
||||
putchr(']');
|
||||
width += len;
|
||||
++indx;
|
||||
}
|
||||
putchr('\n');
|
||||
error((char *)NULL);
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)decode.c 5.9 (Berkeley) 3/1/91"; */
|
||||
static char *rcsid = "$Id: decode.c,v 1.2 1993/11/09 05:08:30 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines to decode user commands.
|
||||
*
|
||||
* This is all table driven.
|
||||
* A command table is a sequence of command descriptors.
|
||||
* Each command descriptor is a sequence of bytes with the following format:
|
||||
* <c1><c2>...<cN><0><action>
|
||||
* The characters c1,c2,...,cN are the command string; that is,
|
||||
* the characters which the user must type.
|
||||
* It is terminated by a null <0> byte.
|
||||
* The byte after the null byte is the action code associated
|
||||
* with the command string.
|
||||
*
|
||||
* The default commands are described by cmdtable.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
#include <stdio.h>
|
||||
#include <less.h>
|
||||
|
||||
/*
|
||||
* Command table is ordered roughly according to expected
|
||||
* frequency of use, so the common commands are near the beginning.
|
||||
*/
|
||||
#define CONTROL(c) ((c)&037)
|
||||
|
||||
static char cmdtable[] = {
|
||||
'\r',0, A_F_LINE,
|
||||
'\n',0, A_F_LINE,
|
||||
's',0, A_F_LINE,
|
||||
'j',0, A_F_LINE,
|
||||
'k',0, A_B_LINE,
|
||||
'd',0, A_F_SCROLL,
|
||||
CONTROL('D'),0, A_F_SCROLL,
|
||||
'f',0, A_F_SCROLL,
|
||||
'u',0, A_B_SCROLL,
|
||||
CONTROL('U'),0, A_B_SCROLL,
|
||||
' ',0, A_F_SCREEN,
|
||||
'z',0, A_F_SCREEN,
|
||||
CONTROL('F'),0, A_F_SCREEN,
|
||||
'b',0, A_B_SCREEN,
|
||||
CONTROL('B'),0, A_B_SCREEN,
|
||||
'R',0, A_FREPAINT,
|
||||
'r',0, A_REPAINT,
|
||||
CONTROL('L'),0, A_REPAINT,
|
||||
'g',0, A_GOLINE,
|
||||
'p',0, A_PERCENT,
|
||||
'%',0, A_PERCENT,
|
||||
'G',0, A_GOEND,
|
||||
'0',0, A_DIGIT,
|
||||
'1',0, A_DIGIT,
|
||||
'2',0, A_DIGIT,
|
||||
'3',0, A_DIGIT,
|
||||
'4',0, A_DIGIT,
|
||||
'5',0, A_DIGIT,
|
||||
'6',0, A_DIGIT,
|
||||
'7',0, A_DIGIT,
|
||||
'8',0, A_DIGIT,
|
||||
'9',0, A_DIGIT,
|
||||
|
||||
'=',0, A_STAT,
|
||||
CONTROL('G'),0, A_STAT,
|
||||
':','f',0, A_STAT,
|
||||
'/',0, A_F_SEARCH,
|
||||
'?',0, A_B_SEARCH,
|
||||
'!',0, A_SHELL,
|
||||
':','!',0, A_SHELL,
|
||||
'n',0, A_AGAIN_SEARCH,
|
||||
'm',0, A_SETMARK,
|
||||
'\'',0, A_GOMARK,
|
||||
'E',0, A_EXAMINE,
|
||||
'N',0, A_NEXT_FILE,
|
||||
':','n',0, A_NEXT_FILE,
|
||||
'P',0, A_PREV_FILE,
|
||||
':','p',0, A_PREV_FILE,
|
||||
'v',0, A_VISUAL,
|
||||
|
||||
'h',0, A_HELP,
|
||||
'q',0, A_QUIT,
|
||||
'Q',0, A_QUIT,
|
||||
':','q',0, A_QUIT,
|
||||
':','t',0, A_TAGFILE,
|
||||
':', 'a', 0, A_FILE_LIST,
|
||||
'Z','Z',0, A_QUIT,
|
||||
};
|
||||
|
||||
char *cmdendtable = cmdtable + sizeof(cmdtable);
|
||||
|
||||
#define MAX_CMDLEN 16
|
||||
|
||||
static char kbuf[MAX_CMDLEN+1];
|
||||
static char *kp = kbuf;
|
||||
|
||||
/*
|
||||
* Indicate that we're not in a prefix command
|
||||
* by resetting the command buffer pointer.
|
||||
*/
|
||||
noprefix()
|
||||
{
|
||||
kp = kbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode a command character and return the associated action.
|
||||
*/
|
||||
cmd_decode(c)
|
||||
int c;
|
||||
{
|
||||
register int action = A_INVALID;
|
||||
|
||||
/*
|
||||
* Append the new command character to the command string in kbuf.
|
||||
*/
|
||||
*kp++ = c;
|
||||
*kp = '\0';
|
||||
|
||||
action = cmd_search(cmdtable, cmdendtable);
|
||||
|
||||
/* This is not a prefix character. */
|
||||
if (action != A_PREFIX)
|
||||
noprefix();
|
||||
return(action);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search a command table for the current command string (in kbuf).
|
||||
*/
|
||||
cmd_search(table, endtable)
|
||||
char *table;
|
||||
char *endtable;
|
||||
{
|
||||
register char *p, *q;
|
||||
|
||||
for (p = table, q = kbuf; p < endtable; p++, q++) {
|
||||
if (*p == *q) {
|
||||
/*
|
||||
* Current characters match.
|
||||
* If we're at the end of the string, we've found it.
|
||||
* Return the action code, which is the character
|
||||
* after the null at the end of the string
|
||||
* in the command table.
|
||||
*/
|
||||
if (*p == '\0')
|
||||
return(p[1]);
|
||||
}
|
||||
else if (*q == '\0') {
|
||||
/*
|
||||
* Hit the end of the user's command,
|
||||
* but not the end of the string in the command table.
|
||||
* The user's command is incomplete.
|
||||
*/
|
||||
return(A_PREFIX);
|
||||
} else {
|
||||
/*
|
||||
* Not a match.
|
||||
* Skip ahead to the next command in the
|
||||
* command table, and reset the pointer
|
||||
* to the user's command.
|
||||
*/
|
||||
while (*p++ != '\0');
|
||||
q = kbuf-1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* No match found in the entire command table.
|
||||
*/
|
||||
return(A_INVALID);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/* $NetBSD: filename.c,v 1.2 1994/12/24 17:17:06 cgd Exp $ */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Expand a string, substituting any "%" with the current filename,
|
||||
* and any "#" with the previous filename and an initial "!" with
|
||||
* the second string.
|
||||
*/
|
||||
char *
|
||||
fexpand(s, t)
|
||||
char *s;
|
||||
char *t;
|
||||
{
|
||||
extern char *current_file, *previous_file;
|
||||
register char *fr, *to;
|
||||
register int n;
|
||||
register char *e;
|
||||
|
||||
if (*s == '\0')
|
||||
return ((char *) 0);
|
||||
/*
|
||||
* Make one pass to see how big a buffer we
|
||||
* need to allocate for the expanded string.
|
||||
*/
|
||||
n = 0;
|
||||
for (fr = s; *fr != '\0'; fr++)
|
||||
{
|
||||
switch (*fr)
|
||||
{
|
||||
case '!':
|
||||
if (s == fr && t == (char *) 0) {
|
||||
error("no previous command");
|
||||
return ((char *) 0);
|
||||
}
|
||||
n += (s == fr) ? strlen(t) : 1;
|
||||
break;
|
||||
case '%':
|
||||
n += (current_file != (char *) 0) ?
|
||||
strlen(current_file) : 1;
|
||||
break;
|
||||
case '#':
|
||||
n += (previous_file != (char *) 0) ?
|
||||
strlen(previous_file) : 1;
|
||||
break;
|
||||
default:
|
||||
n++;
|
||||
if (*fr == '\\') {
|
||||
n++;
|
||||
if (*++fr == '\0') {
|
||||
error("syntax error");
|
||||
return ((char *) 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((e = (char *) calloc(n+1, sizeof(char))) == (char *) 0) {
|
||||
error("cannot allocate memory");
|
||||
quit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now copy the string, expanding any "%" or "#".
|
||||
*/
|
||||
to = e;
|
||||
for (fr = s; *fr != '\0'; fr++)
|
||||
{
|
||||
switch (*fr)
|
||||
{
|
||||
case '!':
|
||||
if (s == fr) {
|
||||
strcpy(to, t);
|
||||
to += strlen(to);
|
||||
} else
|
||||
*to++ = *fr;
|
||||
break;
|
||||
case '%':
|
||||
if (current_file == (char *) 0)
|
||||
*to++ = *fr;
|
||||
else {
|
||||
strcpy(to, current_file);
|
||||
to += strlen(to);
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
if (previous_file == (char *) 0)
|
||||
*to++ = *fr;
|
||||
else {
|
||||
strcpy(to, previous_file);
|
||||
to += strlen(to);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*to++ = *fr;
|
||||
if (*fr == '\\')
|
||||
*to++ = *++fr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*to = '\0';
|
||||
return (e);
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)help.c 5.7 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: help.c,v 1.2 1993/11/09 05:08:46 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <less.h>
|
||||
#include "pathnames.h"
|
||||
|
||||
help()
|
||||
{
|
||||
char cmd[MAXPATHLEN + 20];
|
||||
|
||||
(void)sprintf(cmd, "-more -ce %s", _PATH_HELPFILE);
|
||||
lsystem(cmd);
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: input.c,v 1.2 1993/11/09 05:09:07 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* High level routines dealing with getting lines of input
|
||||
* from the file being viewed.
|
||||
*
|
||||
* When we speak of "lines" here, we mean PRINTABLE lines;
|
||||
* lines processed with respect to the screen width.
|
||||
* We use the term "raw line" to refer to lines simply
|
||||
* delimited by newlines; not processed with respect to screen width.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <less.h>
|
||||
|
||||
extern int squeeze;
|
||||
extern int sigs;
|
||||
extern char *line;
|
||||
|
||||
off_t ch_tell();
|
||||
|
||||
/*
|
||||
* Get the next line.
|
||||
* A "current" position is passed and a "new" position is returned.
|
||||
* The current position is the position of the first character of
|
||||
* a line. The new position is the position of the first character
|
||||
* of the NEXT line. The line obtained is the line starting at curr_pos.
|
||||
*/
|
||||
off_t
|
||||
forw_line(curr_pos)
|
||||
off_t curr_pos;
|
||||
{
|
||||
off_t new_pos;
|
||||
register int c;
|
||||
|
||||
if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
|
||||
return (NULL_POSITION);
|
||||
|
||||
c = ch_forw_get();
|
||||
if (c == EOI)
|
||||
return (NULL_POSITION);
|
||||
|
||||
prewind();
|
||||
for (;;)
|
||||
{
|
||||
if (sigs)
|
||||
return (NULL_POSITION);
|
||||
if (c == '\n' || c == EOI)
|
||||
{
|
||||
/*
|
||||
* End of the line.
|
||||
*/
|
||||
new_pos = ch_tell();
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the char to the line and get the next char.
|
||||
*/
|
||||
if (pappend(c))
|
||||
{
|
||||
/*
|
||||
* The char won't fit in the line; the line
|
||||
* is too long to print in the screen width.
|
||||
* End the line here.
|
||||
*/
|
||||
new_pos = ch_tell() - 1;
|
||||
break;
|
||||
}
|
||||
c = ch_forw_get();
|
||||
}
|
||||
(void) pappend('\0');
|
||||
|
||||
if (squeeze && *line == '\0')
|
||||
{
|
||||
/*
|
||||
* This line is blank.
|
||||
* Skip down to the last contiguous blank line
|
||||
* and pretend it is the one which we are returning.
|
||||
*/
|
||||
while ((c = ch_forw_get()) == '\n')
|
||||
if (sigs)
|
||||
return (NULL_POSITION);
|
||||
if (c != EOI)
|
||||
(void) ch_back_get();
|
||||
new_pos = ch_tell();
|
||||
}
|
||||
|
||||
return (new_pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the previous line.
|
||||
* A "current" position is passed and a "new" position is returned.
|
||||
* The current position is the position of the first character of
|
||||
* a line. The new position is the position of the first character
|
||||
* of the PREVIOUS line. The line obtained is the one starting at new_pos.
|
||||
*/
|
||||
off_t
|
||||
back_line(curr_pos)
|
||||
off_t curr_pos;
|
||||
{
|
||||
off_t new_pos, begin_new_pos;
|
||||
int c;
|
||||
|
||||
if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
|
||||
ch_seek(curr_pos-1))
|
||||
return (NULL_POSITION);
|
||||
|
||||
if (squeeze)
|
||||
{
|
||||
/*
|
||||
* Find out if the "current" line was blank.
|
||||
*/
|
||||
(void) ch_forw_get(); /* Skip the newline */
|
||||
c = ch_forw_get(); /* First char of "current" line */
|
||||
(void) ch_back_get(); /* Restore our position */
|
||||
(void) ch_back_get();
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
/*
|
||||
* The "current" line was blank.
|
||||
* Skip over any preceeding blank lines,
|
||||
* since we skipped them in forw_line().
|
||||
*/
|
||||
while ((c = ch_back_get()) == '\n')
|
||||
if (sigs)
|
||||
return (NULL_POSITION);
|
||||
if (c == EOI)
|
||||
return (NULL_POSITION);
|
||||
(void) ch_forw_get();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan backwards until we hit the beginning of the line.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
if (sigs)
|
||||
return (NULL_POSITION);
|
||||
c = ch_back_get();
|
||||
if (c == '\n')
|
||||
{
|
||||
/*
|
||||
* This is the newline ending the previous line.
|
||||
* We have hit the beginning of the line.
|
||||
*/
|
||||
new_pos = ch_tell() + 1;
|
||||
break;
|
||||
}
|
||||
if (c == EOI)
|
||||
{
|
||||
/*
|
||||
* We have hit the beginning of the file.
|
||||
* This must be the first line in the file.
|
||||
* This must, of course, be the beginning of the line.
|
||||
*/
|
||||
new_pos = ch_tell();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now scan forwards from the beginning of this line.
|
||||
* We keep discarding "printable lines" (based on screen width)
|
||||
* until we reach the curr_pos.
|
||||
*
|
||||
* {{ This algorithm is pretty inefficient if the lines
|
||||
* are much longer than the screen width,
|
||||
* but I don't know of any better way. }}
|
||||
*/
|
||||
if (ch_seek(new_pos))
|
||||
return (NULL_POSITION);
|
||||
loop:
|
||||
begin_new_pos = new_pos;
|
||||
prewind();
|
||||
|
||||
do
|
||||
{
|
||||
c = ch_forw_get();
|
||||
if (c == EOI || sigs)
|
||||
return (NULL_POSITION);
|
||||
new_pos++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (pappend(c))
|
||||
{
|
||||
/*
|
||||
* Got a full printable line, but we haven't
|
||||
* reached our curr_pos yet. Discard the line
|
||||
* and start a new one.
|
||||
*/
|
||||
(void) pappend('\0');
|
||||
(void) ch_back_get();
|
||||
new_pos--;
|
||||
goto loop;
|
||||
}
|
||||
} while (new_pos < curr_pos);
|
||||
|
||||
(void) pappend('\0');
|
||||
|
||||
return (begin_new_pos);
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)less.h 5.9 (Berkeley) 6/1/90
|
||||
* $Id: less.h,v 1.2 1993/11/09 05:09:24 cgd Exp $
|
||||
*/
|
||||
|
||||
#undef RECOMP
|
||||
|
||||
#define NULL_POSITION ((off_t)(-1))
|
||||
|
||||
#define EOI (0)
|
||||
#define READ_INTR (-2)
|
||||
|
||||
/* Special chars used to tell put_line() to do something special */
|
||||
#define UL_CHAR '\201' /* Enter underline mode */
|
||||
#define UE_CHAR '\202' /* Exit underline mode */
|
||||
#define BO_CHAR '\203' /* Enter boldface mode */
|
||||
#define BE_CHAR '\204' /* Exit boldface mode */
|
||||
|
||||
#define CONTROL_CHAR(c) (iscntrl(c))
|
||||
#define CARAT_CHAR(c) ((c == '\177') ? '?' : (c | 0100))
|
||||
|
||||
#define TOP (0)
|
||||
#define TOP_PLUS_ONE (1)
|
||||
#define BOTTOM (-1)
|
||||
#define BOTTOM_PLUS_ONE (-2)
|
||||
#define MIDDLE (-3)
|
||||
|
||||
#define A_INVALID -1
|
||||
|
||||
#define A_AGAIN_SEARCH 1
|
||||
#define A_B_LINE 2
|
||||
#define A_B_SCREEN 3
|
||||
#define A_B_SCROLL 4
|
||||
#define A_B_SEARCH 5
|
||||
#define A_DIGIT 6
|
||||
#define A_EXAMINE 7
|
||||
#define A_FREPAINT 8
|
||||
#define A_F_LINE 9
|
||||
#define A_F_SCREEN 10
|
||||
#define A_F_SCROLL 11
|
||||
#define A_F_SEARCH 12
|
||||
#define A_GOEND 13
|
||||
#define A_GOLINE 14
|
||||
#define A_GOMARK 15
|
||||
#define A_HELP 16
|
||||
#define A_NEXT_FILE 17
|
||||
#define A_PERCENT 18
|
||||
#define A_PREFIX 19
|
||||
#define A_PREV_FILE 20
|
||||
#define A_QUIT 21
|
||||
#define A_REPAINT 22
|
||||
#define A_SETMARK 23
|
||||
#define A_STAT 24
|
||||
#define A_VISUAL 25
|
||||
#define A_TAGFILE 26
|
||||
#define A_FILE_LIST 27
|
||||
#define A_SHELL 28
|
@ -1,509 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)line.c 5.5 (Berkeley) 7/24/91"; */
|
||||
static char *rcsid = "$Id: line.c,v 1.2 1993/11/09 05:09:49 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines to manipulate the "line buffer".
|
||||
* The line buffer holds a line of output as it is being built
|
||||
* in preparation for output to the screen.
|
||||
* We keep track of the PRINTABLE length of the line as it is being built.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <less.h>
|
||||
|
||||
static char linebuf[1024]; /* Buffer which holds the current output line */
|
||||
static char *curr; /* Pointer into linebuf */
|
||||
static int column; /* Printable length, accounting for
|
||||
backspaces, etc. */
|
||||
/*
|
||||
* A ridiculously complex state machine takes care of backspaces. The
|
||||
* complexity arises from the attempt to deal with all cases, especially
|
||||
* involving long lines with underlining, boldfacing or whatever. There
|
||||
* are still some cases which will break it.
|
||||
*
|
||||
* There are four states:
|
||||
* LN_NORMAL is the normal state (not in underline mode).
|
||||
* LN_UNDERLINE means we are in underline mode. We expect to get
|
||||
* either a sequence like "_\bX" or "X\b_" to continue
|
||||
* underline mode, or anything else to end underline mode.
|
||||
* LN_BOLDFACE means we are in boldface mode. We expect to get sequences
|
||||
* like "X\bX\b...X\bX" to continue boldface mode, or anything
|
||||
* else to end boldface mode.
|
||||
* LN_UL_X means we are one character after LN_UNDERLINE
|
||||
* (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
|
||||
* LN_UL_XB means we are one character after LN_UL_X
|
||||
* (we have gotten the backspace in "_\bX" or "X\b_";
|
||||
* we expect one more ordinary character,
|
||||
* which will put us back in state LN_UNDERLINE).
|
||||
* LN_BO_X means we are one character after LN_BOLDFACE
|
||||
* (we have gotten the 'X' in "X\bX").
|
||||
* LN_BO_XB means we are one character after LN_BO_X
|
||||
* (we have gotten the backspace in "X\bX";
|
||||
* we expect one more 'X' which will put us back
|
||||
* in LN_BOLDFACE).
|
||||
*/
|
||||
static int ln_state; /* Currently in normal/underline/bold/etc mode? */
|
||||
#define LN_NORMAL 0 /* Not in underline, boldface or whatever mode */
|
||||
#define LN_UNDERLINE 1 /* In underline, need next char */
|
||||
#define LN_UL_X 2 /* In underline, got char, need \b */
|
||||
#define LN_UL_XB 3 /* In underline, got char & \b, need one more */
|
||||
#define LN_BOLDFACE 4 /* In boldface, need next char */
|
||||
#define LN_BO_X 5 /* In boldface, got char, need \b */
|
||||
#define LN_BO_XB 6 /* In boldface, got char & \b, need same char */
|
||||
|
||||
char *line; /* Pointer to the current line.
|
||||
Usually points to linebuf. */
|
||||
|
||||
extern int bs_mode;
|
||||
extern int tabstop;
|
||||
extern int bo_width, be_width;
|
||||
extern int ul_width, ue_width;
|
||||
extern int sc_width, sc_height;
|
||||
|
||||
/*
|
||||
* Rewind the line buffer.
|
||||
*/
|
||||
prewind()
|
||||
{
|
||||
line = curr = linebuf;
|
||||
ln_state = LN_NORMAL;
|
||||
column = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a character to the line buffer.
|
||||
* Expand tabs into spaces, handle underlining, boldfacing, etc.
|
||||
* Returns 0 if ok, 1 if couldn't fit in buffer.
|
||||
*/
|
||||
#define NEW_COLUMN(addon) \
|
||||
if (column + addon + (ln_state ? ue_width : 0) > sc_width) \
|
||||
return(1); \
|
||||
else \
|
||||
column += addon
|
||||
|
||||
pappend(c)
|
||||
int c;
|
||||
{
|
||||
if (c == '\0') {
|
||||
/*
|
||||
* Terminate any special modes, if necessary.
|
||||
* Append a '\0' to the end of the line.
|
||||
*/
|
||||
switch (ln_state) {
|
||||
case LN_UL_X:
|
||||
curr[0] = curr[-1];
|
||||
curr[-1] = UE_CHAR;
|
||||
curr++;
|
||||
break;
|
||||
case LN_BO_X:
|
||||
curr[0] = curr[-1];
|
||||
curr[-1] = BE_CHAR;
|
||||
curr++;
|
||||
break;
|
||||
case LN_UL_XB:
|
||||
case LN_UNDERLINE:
|
||||
*curr++ = UE_CHAR;
|
||||
break;
|
||||
case LN_BO_XB:
|
||||
case LN_BOLDFACE:
|
||||
*curr++ = BE_CHAR;
|
||||
break;
|
||||
}
|
||||
ln_state = LN_NORMAL;
|
||||
*curr = '\0';
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (curr > linebuf + sizeof(linebuf) - 12)
|
||||
/*
|
||||
* Almost out of room in the line buffer.
|
||||
* Don't take any chances.
|
||||
* {{ Linebuf is supposed to be big enough that this
|
||||
* will never happen, but may need to be made
|
||||
* bigger for wide screens or lots of backspaces. }}
|
||||
*/
|
||||
return(1);
|
||||
|
||||
if (!bs_mode) {
|
||||
/*
|
||||
* Advance the state machine.
|
||||
*/
|
||||
switch (ln_state) {
|
||||
case LN_NORMAL:
|
||||
if (curr <= linebuf + 1
|
||||
|| curr[-1] != (char)('H' | 0200))
|
||||
break;
|
||||
column -= 2;
|
||||
if (c == curr[-2])
|
||||
goto enter_boldface;
|
||||
if (c == '_' || curr[-2] == '_')
|
||||
goto enter_underline;
|
||||
curr -= 2;
|
||||
break;
|
||||
|
||||
enter_boldface:
|
||||
/*
|
||||
* We have "X\bX" (including the current char).
|
||||
* Switch into boldface mode.
|
||||
*/
|
||||
column--;
|
||||
if (column + bo_width + be_width + 1 >= sc_width)
|
||||
/*
|
||||
* Not enough room left on the screen to
|
||||
* enter and exit boldface mode.
|
||||
*/
|
||||
return (1);
|
||||
|
||||
if (bo_width > 0 && curr > linebuf + 2
|
||||
&& curr[-3] == ' ') {
|
||||
/*
|
||||
* Special case for magic cookie terminals:
|
||||
* if the previous char was a space, replace
|
||||
* it with the "enter boldface" sequence.
|
||||
*/
|
||||
curr[-3] = BO_CHAR;
|
||||
column += bo_width-1;
|
||||
} else {
|
||||
curr[-1] = curr[-2];
|
||||
curr[-2] = BO_CHAR;
|
||||
column += bo_width;
|
||||
curr++;
|
||||
}
|
||||
goto ln_bo_xb_case;
|
||||
|
||||
enter_underline:
|
||||
/*
|
||||
* We have either "_\bX" or "X\b_" (including
|
||||
* the current char). Switch into underline mode.
|
||||
*/
|
||||
column--;
|
||||
if (column + ul_width + ue_width + 1 >= sc_width)
|
||||
/*
|
||||
* Not enough room left on the screen to
|
||||
* enter and exit underline mode.
|
||||
*/
|
||||
return (1);
|
||||
|
||||
if (ul_width > 0 &&
|
||||
curr > linebuf + 2 && curr[-3] == ' ')
|
||||
{
|
||||
/*
|
||||
* Special case for magic cookie terminals:
|
||||
* if the previous char was a space, replace
|
||||
* it with the "enter underline" sequence.
|
||||
*/
|
||||
curr[-3] = UL_CHAR;
|
||||
column += ul_width-1;
|
||||
} else
|
||||
{
|
||||
curr[-1] = curr[-2];
|
||||
curr[-2] = UL_CHAR;
|
||||
column += ul_width;
|
||||
curr++;
|
||||
}
|
||||
goto ln_ul_xb_case;
|
||||
/*NOTREACHED*/
|
||||
case LN_UL_XB:
|
||||
/*
|
||||
* Termination of a sequence "_\bX" or "X\b_".
|
||||
*/
|
||||
if (c != '_' && curr[-2] != '_' && c == curr[-2])
|
||||
{
|
||||
/*
|
||||
* We seem to have run on from underlining
|
||||
* into boldfacing - this is a nasty fix, but
|
||||
* until this whole routine is rewritten as a
|
||||
* real DFA, ... well ...
|
||||
*/
|
||||
curr[0] = curr[-2];
|
||||
curr[-2] = UE_CHAR;
|
||||
curr[-1] = BO_CHAR;
|
||||
curr += 2; /* char & non-existent backspace */
|
||||
ln_state = LN_BO_XB;
|
||||
goto ln_bo_xb_case;
|
||||
}
|
||||
ln_ul_xb_case:
|
||||
if (c == '_')
|
||||
c = curr[-2];
|
||||
curr -= 2;
|
||||
ln_state = LN_UNDERLINE;
|
||||
break;
|
||||
case LN_BO_XB:
|
||||
/*
|
||||
* Termination of a sequnce "X\bX".
|
||||
*/
|
||||
if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
|
||||
{
|
||||
/*
|
||||
* We seem to have run on from
|
||||
* boldfacing into underlining.
|
||||
*/
|
||||
curr[0] = curr[-2];
|
||||
curr[-2] = BE_CHAR;
|
||||
curr[-1] = UL_CHAR;
|
||||
curr += 2; /* char & non-existent backspace */
|
||||
ln_state = LN_UL_XB;
|
||||
goto ln_ul_xb_case;
|
||||
}
|
||||
ln_bo_xb_case:
|
||||
curr -= 2;
|
||||
ln_state = LN_BOLDFACE;
|
||||
break;
|
||||
case LN_UNDERLINE:
|
||||
if (column + ue_width + bo_width + 1 + be_width >= sc_width)
|
||||
/*
|
||||
* We have just barely enough room to
|
||||
* exit underline mode and handle a possible
|
||||
* underline/boldface run on mixup.
|
||||
*/
|
||||
return (1);
|
||||
ln_state = LN_UL_X;
|
||||
break;
|
||||
case LN_BOLDFACE:
|
||||
if (c == '\b')
|
||||
{
|
||||
ln_state = LN_BO_XB;
|
||||
break;
|
||||
}
|
||||
if (column + be_width + ul_width + 1 + ue_width >= sc_width)
|
||||
/*
|
||||
* We have just barely enough room to
|
||||
* exit underline mode and handle a possible
|
||||
* underline/boldface run on mixup.
|
||||
*/
|
||||
return (1);
|
||||
ln_state = LN_BO_X;
|
||||
break;
|
||||
case LN_UL_X:
|
||||
if (c == '\b')
|
||||
ln_state = LN_UL_XB;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Exit underline mode.
|
||||
* We have to shuffle the chars a bit
|
||||
* to make this work.
|
||||
*/
|
||||
curr[0] = curr[-1];
|
||||
curr[-1] = UE_CHAR;
|
||||
column += ue_width;
|
||||
if (ue_width > 0 && curr[0] == ' ')
|
||||
/*
|
||||
* Another special case for magic
|
||||
* cookie terminals: if the next
|
||||
* char is a space, replace it
|
||||
* with the "exit underline" sequence.
|
||||
*/
|
||||
column--;
|
||||
else
|
||||
curr++;
|
||||
ln_state = LN_NORMAL;
|
||||
}
|
||||
break;
|
||||
case LN_BO_X:
|
||||
if (c == '\b')
|
||||
ln_state = LN_BO_XB;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Exit boldface mode.
|
||||
* We have to shuffle the chars a bit
|
||||
* to make this work.
|
||||
*/
|
||||
curr[0] = curr[-1];
|
||||
curr[-1] = BE_CHAR;
|
||||
column += be_width;
|
||||
if (be_width > 0 && curr[0] == ' ')
|
||||
/*
|
||||
* Another special case for magic
|
||||
* cookie terminals: if the next
|
||||
* char is a space, replace it
|
||||
* with the "exit boldface" sequence.
|
||||
*/
|
||||
column--;
|
||||
else
|
||||
curr++;
|
||||
ln_state = LN_NORMAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '\t') {
|
||||
/*
|
||||
* Expand a tab into spaces.
|
||||
*/
|
||||
do {
|
||||
NEW_COLUMN(1);
|
||||
} while ((column % tabstop) != 0);
|
||||
*curr++ = '\t';
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (c == '\b') {
|
||||
if (ln_state == LN_NORMAL)
|
||||
NEW_COLUMN(2);
|
||||
else
|
||||
column--;
|
||||
*curr++ = ('H' | 0200);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (CONTROL_CHAR(c)) {
|
||||
/*
|
||||
* Put a "^X" into the buffer. The 0200 bit is used to tell
|
||||
* put_line() to prefix the char with a ^. We don't actually
|
||||
* put the ^ in the buffer because we sometimes need to move
|
||||
* chars around, and such movement might separate the ^ from
|
||||
* its following character.
|
||||
*/
|
||||
NEW_COLUMN(2);
|
||||
*curr++ = (CARAT_CHAR(c) | 0200);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ordinary character. Just put it in the buffer.
|
||||
*/
|
||||
NEW_COLUMN(1);
|
||||
*curr++ = c;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analogous to forw_line(), but deals with "raw lines":
|
||||
* lines which are not split for screen width.
|
||||
* {{ This is supposed to be more efficient than forw_line(). }}
|
||||
*/
|
||||
off_t
|
||||
forw_raw_line(curr_pos)
|
||||
off_t curr_pos;
|
||||
{
|
||||
register char *p;
|
||||
register int c;
|
||||
off_t new_pos, ch_tell();
|
||||
|
||||
if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
|
||||
(c = ch_forw_get()) == EOI)
|
||||
return (NULL_POSITION);
|
||||
|
||||
p = linebuf;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (c == '\n' || c == EOI)
|
||||
{
|
||||
new_pos = ch_tell();
|
||||
break;
|
||||
}
|
||||
if (p >= &linebuf[sizeof(linebuf)-1])
|
||||
{
|
||||
/*
|
||||
* Overflowed the input buffer.
|
||||
* Pretend the line ended here.
|
||||
* {{ The line buffer is supposed to be big
|
||||
* enough that this never happens. }}
|
||||
*/
|
||||
new_pos = ch_tell() - 1;
|
||||
break;
|
||||
}
|
||||
*p++ = c;
|
||||
c = ch_forw_get();
|
||||
}
|
||||
*p = '\0';
|
||||
line = linebuf;
|
||||
return (new_pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analogous to back_line(), but deals with "raw lines".
|
||||
* {{ This is supposed to be more efficient than back_line(). }}
|
||||
*/
|
||||
off_t
|
||||
back_raw_line(curr_pos)
|
||||
off_t curr_pos;
|
||||
{
|
||||
register char *p;
|
||||
register int c;
|
||||
off_t new_pos, ch_tell();
|
||||
|
||||
if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
|
||||
ch_seek(curr_pos-1))
|
||||
return (NULL_POSITION);
|
||||
|
||||
p = &linebuf[sizeof(linebuf)];
|
||||
*--p = '\0';
|
||||
|
||||
for (;;)
|
||||
{
|
||||
c = ch_back_get();
|
||||
if (c == '\n')
|
||||
{
|
||||
/*
|
||||
* This is the newline ending the previous line.
|
||||
* We have hit the beginning of the line.
|
||||
*/
|
||||
new_pos = ch_tell() + 1;
|
||||
break;
|
||||
}
|
||||
if (c == EOI)
|
||||
{
|
||||
/*
|
||||
* We have hit the beginning of the file.
|
||||
* This must be the first line in the file.
|
||||
* This must, of course, be the beginning of the line.
|
||||
*/
|
||||
new_pos = (off_t)0;
|
||||
break;
|
||||
}
|
||||
if (p <= linebuf)
|
||||
{
|
||||
/*
|
||||
* Overflowed the input buffer.
|
||||
* Pretend the line ended here.
|
||||
*/
|
||||
new_pos = ch_tell() + 1;
|
||||
break;
|
||||
}
|
||||
*--p = c;
|
||||
}
|
||||
line = p;
|
||||
return (new_pos);
|
||||
}
|
@ -1,384 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)linenum.c 5.6 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: linenum.c,v 1.2 1993/11/09 05:10:02 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Code to handle displaying line numbers.
|
||||
*
|
||||
* Finding the line number of a given file position is rather tricky.
|
||||
* We don't want to just start at the beginning of the file and
|
||||
* count newlines, because that is slow for large files (and also
|
||||
* wouldn't work if we couldn't get to the start of the file; e.g.
|
||||
* if input is a long pipe).
|
||||
*
|
||||
* So we use the function add_lnum to cache line numbers.
|
||||
* We try to be very clever and keep only the more interesting
|
||||
* line numbers when we run out of space in our table. A line
|
||||
* number is more interesting than another when it is far from
|
||||
* other line numbers. For example, we'd rather keep lines
|
||||
* 100,200,300 than 100,101,300. 200 is more interesting than
|
||||
* 101 because 101 can be derived very cheaply from 100, while
|
||||
* 200 is more expensive to derive from 100.
|
||||
*
|
||||
* The function currline() returns the line number of a given
|
||||
* position in the file. As a side effect, it calls add_lnum
|
||||
* to cache the line number. Therefore currline is occasionally
|
||||
* called to make sure we cache line numbers often enough.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <less.h>
|
||||
|
||||
/*
|
||||
* Structure to keep track of a line number and the associated file position.
|
||||
* A doubly-linked circular list of line numbers is kept ordered by line number.
|
||||
*/
|
||||
struct linenum
|
||||
{
|
||||
struct linenum *next; /* Link to next in the list */
|
||||
struct linenum *prev; /* Line to previous in the list */
|
||||
off_t pos; /* File position */
|
||||
off_t gap; /* Gap between prev and next */
|
||||
int line; /* Line number */
|
||||
};
|
||||
/*
|
||||
* "gap" needs some explanation: the gap of any particular line number
|
||||
* is the distance between the previous one and the next one in the list.
|
||||
* ("Distance" means difference in file position.) In other words, the
|
||||
* gap of a line number is the gap which would be introduced if this
|
||||
* line number were deleted. It is used to decide which one to replace
|
||||
* when we have a new one to insert and the table is full.
|
||||
*/
|
||||
|
||||
#define NPOOL 50 /* Size of line number pool */
|
||||
|
||||
#define LONGTIME (2) /* In seconds */
|
||||
|
||||
int lnloop = 0; /* Are we in the line num loop? */
|
||||
|
||||
static struct linenum anchor; /* Anchor of the list */
|
||||
static struct linenum *freelist; /* Anchor of the unused entries */
|
||||
static struct linenum pool[NPOOL]; /* The pool itself */
|
||||
static struct linenum *spare; /* We always keep one spare entry */
|
||||
|
||||
extern int linenums;
|
||||
extern int sigs;
|
||||
|
||||
/*
|
||||
* Initialize the line number structures.
|
||||
*/
|
||||
clr_linenum()
|
||||
{
|
||||
register struct linenum *p;
|
||||
|
||||
/*
|
||||
* Put all the entries on the free list.
|
||||
* Leave one for the "spare".
|
||||
*/
|
||||
for (p = pool; p < &pool[NPOOL-2]; p++)
|
||||
p->next = p+1;
|
||||
pool[NPOOL-2].next = NULL;
|
||||
freelist = pool;
|
||||
|
||||
spare = &pool[NPOOL-1];
|
||||
|
||||
/*
|
||||
* Initialize the anchor.
|
||||
*/
|
||||
anchor.next = anchor.prev = &anchor;
|
||||
anchor.gap = 0;
|
||||
anchor.pos = (off_t)0;
|
||||
anchor.line = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the gap for an entry.
|
||||
*/
|
||||
static
|
||||
calcgap(p)
|
||||
register struct linenum *p;
|
||||
{
|
||||
/*
|
||||
* Don't bother to compute a gap for the anchor.
|
||||
* Also don't compute a gap for the last one in the list.
|
||||
* The gap for that last one should be considered infinite,
|
||||
* but we never look at it anyway.
|
||||
*/
|
||||
if (p == &anchor || p->next == &anchor)
|
||||
return;
|
||||
p->gap = p->next->pos - p->prev->pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new line number to the cache.
|
||||
* The specified position (pos) should be the file position of the
|
||||
* FIRST character in the specified line.
|
||||
*/
|
||||
add_lnum(line, pos)
|
||||
int line;
|
||||
off_t pos;
|
||||
{
|
||||
register struct linenum *p;
|
||||
register struct linenum *new;
|
||||
register struct linenum *nextp;
|
||||
register struct linenum *prevp;
|
||||
register off_t mingap;
|
||||
|
||||
/*
|
||||
* Find the proper place in the list for the new one.
|
||||
* The entries are sorted by position.
|
||||
*/
|
||||
for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next)
|
||||
if (p->line == line)
|
||||
/* We already have this one. */
|
||||
return;
|
||||
nextp = p;
|
||||
prevp = p->prev;
|
||||
|
||||
if (freelist != NULL)
|
||||
{
|
||||
/*
|
||||
* We still have free (unused) entries.
|
||||
* Use one of them.
|
||||
*/
|
||||
new = freelist;
|
||||
freelist = freelist->next;
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* No free entries.
|
||||
* Use the "spare" entry.
|
||||
*/
|
||||
new = spare;
|
||||
spare = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the fields of the new entry,
|
||||
* and insert it into the proper place in the list.
|
||||
*/
|
||||
new->next = nextp;
|
||||
new->prev = prevp;
|
||||
new->pos = pos;
|
||||
new->line = line;
|
||||
|
||||
nextp->prev = new;
|
||||
prevp->next = new;
|
||||
|
||||
/*
|
||||
* Recalculate gaps for the new entry and the neighboring entries.
|
||||
*/
|
||||
calcgap(new);
|
||||
calcgap(nextp);
|
||||
calcgap(prevp);
|
||||
|
||||
if (spare == NULL)
|
||||
{
|
||||
/*
|
||||
* We have used the spare entry.
|
||||
* Scan the list to find the one with the smallest
|
||||
* gap, take it out and make it the spare.
|
||||
* We should never remove the last one, so stop when
|
||||
* we get to p->next == &anchor. This also avoids
|
||||
* looking at the gap of the last one, which is
|
||||
* not computed by calcgap.
|
||||
*/
|
||||
mingap = anchor.next->gap;
|
||||
for (p = anchor.next; p->next != &anchor; p = p->next)
|
||||
{
|
||||
if (p->gap <= mingap)
|
||||
{
|
||||
spare = p;
|
||||
mingap = p->gap;
|
||||
}
|
||||
}
|
||||
spare->next->prev = spare->prev;
|
||||
spare->prev->next = spare->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get stuck in a long loop trying to figure out the
|
||||
* line number, print a message to tell the user what we're doing.
|
||||
*/
|
||||
static
|
||||
longloopmessage()
|
||||
{
|
||||
ierror("Calculating line numbers");
|
||||
/*
|
||||
* Set the lnloop flag here, so if the user interrupts while
|
||||
* we are calculating line numbers, the signal handler will
|
||||
* turn off line numbers (linenums=0).
|
||||
*/
|
||||
lnloop = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the line number associated with a given position.
|
||||
* Return 0 if we can't figure it out.
|
||||
*/
|
||||
find_linenum(pos)
|
||||
off_t pos;
|
||||
{
|
||||
register struct linenum *p;
|
||||
register int lno;
|
||||
register int loopcount;
|
||||
off_t cpos, back_raw_line(), forw_raw_line();
|
||||
time_t startime, time();
|
||||
|
||||
if (!linenums)
|
||||
/*
|
||||
* We're not using line numbers.
|
||||
*/
|
||||
return (0);
|
||||
if (pos == NULL_POSITION)
|
||||
/*
|
||||
* Caller doesn't know what he's talking about.
|
||||
*/
|
||||
return (0);
|
||||
if (pos == (off_t)0)
|
||||
/*
|
||||
* Beginning of file is always line number 1.
|
||||
*/
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* Find the entry nearest to the position we want.
|
||||
*/
|
||||
for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next)
|
||||
continue;
|
||||
if (p->pos == pos)
|
||||
/* Found it exactly. */
|
||||
return (p->line);
|
||||
|
||||
/*
|
||||
* This is the (possibly) time-consuming part.
|
||||
* We start at the line we just found and start
|
||||
* reading the file forward or backward till we
|
||||
* get to the place we want.
|
||||
*
|
||||
* First decide whether we should go forward from the
|
||||
* previous one or backwards from the next one.
|
||||
* The decision is based on which way involves
|
||||
* traversing fewer bytes in the file.
|
||||
*/
|
||||
flush();
|
||||
(void)time(&startime);
|
||||
if (p == &anchor || pos - p->prev->pos < p->pos - pos)
|
||||
{
|
||||
/*
|
||||
* Go forward.
|
||||
*/
|
||||
p = p->prev;
|
||||
if (ch_seek(p->pos))
|
||||
return (0);
|
||||
loopcount = 0;
|
||||
for (lno = p->line, cpos = p->pos; cpos < pos; lno++)
|
||||
{
|
||||
/*
|
||||
* Allow a signal to abort this loop.
|
||||
*/
|
||||
cpos = forw_raw_line(cpos);
|
||||
if (sigs || cpos == NULL_POSITION)
|
||||
return (0);
|
||||
if (loopcount >= 0 && ++loopcount > 100) {
|
||||
loopcount = 0;
|
||||
if (time((time_t *)NULL)
|
||||
>= startime + LONGTIME) {
|
||||
longloopmessage();
|
||||
loopcount = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
lnloop = 0;
|
||||
/*
|
||||
* If the given position is not at the start of a line,
|
||||
* make sure we return the correct line number.
|
||||
*/
|
||||
if (cpos > pos)
|
||||
lno--;
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Go backward.
|
||||
*/
|
||||
if (ch_seek(p->pos))
|
||||
return (0);
|
||||
loopcount = 0;
|
||||
for (lno = p->line, cpos = p->pos; cpos > pos; lno--)
|
||||
{
|
||||
/*
|
||||
* Allow a signal to abort this loop.
|
||||
*/
|
||||
cpos = back_raw_line(cpos);
|
||||
if (sigs || cpos == NULL_POSITION)
|
||||
return (0);
|
||||
if (loopcount >= 0 && ++loopcount > 100) {
|
||||
loopcount = 0;
|
||||
if (time((time_t *)NULL)
|
||||
>= startime + LONGTIME) {
|
||||
longloopmessage();
|
||||
loopcount = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
lnloop = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We might as well cache it.
|
||||
*/
|
||||
add_lnum(lno, cpos);
|
||||
return (lno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the line number of the "current" line.
|
||||
* The argument "where" tells which line is to be considered
|
||||
* the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc).
|
||||
*/
|
||||
currline(where)
|
||||
int where;
|
||||
{
|
||||
off_t pos, ch_length(), position();
|
||||
|
||||
if ((pos = position(where)) == NULL_POSITION)
|
||||
pos = ch_length();
|
||||
return(find_linenum(pos));
|
||||
}
|
@ -1,369 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1988 Mark Nudleman.\n\
|
||||
@(#) Copyright (c) 1988 Regents of the University of California.\n\
|
||||
All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)main.c 5.13 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: main.c,v 1.3 1994/12/24 17:17:09 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Entry point, initialization, miscellaneous routines.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <less.h>
|
||||
|
||||
int ispipe;
|
||||
int new_file;
|
||||
int is_tty;
|
||||
char *current_file, *previous_file, *current_name, *next_name;
|
||||
off_t prev_pos;
|
||||
int any_display;
|
||||
int scroll;
|
||||
int ac;
|
||||
char **av;
|
||||
int curr_ac;
|
||||
int quitting;
|
||||
|
||||
extern int file;
|
||||
extern int cbufs;
|
||||
extern int errmsgs;
|
||||
|
||||
extern char *tagfile;
|
||||
extern int tagoption;
|
||||
|
||||
/*
|
||||
* Edit a new file.
|
||||
* Filename "-" means standard input.
|
||||
* No filename means the "current" file, from the command line.
|
||||
*/
|
||||
edit(filename)
|
||||
register char *filename;
|
||||
{
|
||||
extern int errno;
|
||||
register int f;
|
||||
register char *m;
|
||||
off_t initial_pos, position();
|
||||
static int didpipe;
|
||||
char message[100], *p;
|
||||
char *rindex(), *strerror(), *save(), *bad_file();
|
||||
|
||||
initial_pos = NULL_POSITION;
|
||||
if (filename == NULL || *filename == '\0') {
|
||||
if (curr_ac >= ac) {
|
||||
error("No current file");
|
||||
return(0);
|
||||
}
|
||||
filename = save(av[curr_ac]);
|
||||
}
|
||||
else if (strcmp(filename, "#") == 0) {
|
||||
if (*previous_file == '\0') {
|
||||
error("no previous file");
|
||||
return(0);
|
||||
}
|
||||
filename = save(previous_file);
|
||||
initial_pos = prev_pos;
|
||||
} else
|
||||
filename = save(filename);
|
||||
|
||||
/* use standard input. */
|
||||
if (!strcmp(filename, "-")) {
|
||||
if (didpipe) {
|
||||
error("Can view standard input only once");
|
||||
return(0);
|
||||
}
|
||||
f = 0;
|
||||
}
|
||||
else if ((m = bad_file(filename, message, sizeof(message))) != NULL) {
|
||||
error(m);
|
||||
free(filename);
|
||||
return(0);
|
||||
}
|
||||
else if ((f = open(filename, O_RDONLY, 0)) < 0) {
|
||||
(void)sprintf(message, "%s: %s", filename, strerror(errno));
|
||||
error(message);
|
||||
free(filename);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (isatty(f)) {
|
||||
/*
|
||||
* Not really necessary to call this an error,
|
||||
* but if the control terminal (for commands)
|
||||
* and the input file (for data) are the same,
|
||||
* we get weird results at best.
|
||||
*/
|
||||
error("Can't take input from a terminal");
|
||||
if (f > 0)
|
||||
(void)close(f);
|
||||
(void)free(filename);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are now committed to using the new file.
|
||||
* Close the current input file and set up to use the new one.
|
||||
*/
|
||||
if (file > 0)
|
||||
(void)close(file);
|
||||
new_file = 1;
|
||||
if (previous_file != NULL)
|
||||
free(previous_file);
|
||||
previous_file = current_file;
|
||||
current_file = filename;
|
||||
pos_clear();
|
||||
prev_pos = position(TOP);
|
||||
ispipe = (f == 0);
|
||||
if (ispipe) {
|
||||
didpipe = 1;
|
||||
current_name = "stdin";
|
||||
} else
|
||||
current_name = (p = rindex(filename, '/')) ? p + 1 : filename;
|
||||
if (curr_ac >= ac)
|
||||
next_name = NULL;
|
||||
else
|
||||
next_name = av[curr_ac + 1];
|
||||
file = f;
|
||||
ch_init(cbufs, 0);
|
||||
init_mark();
|
||||
|
||||
if (is_tty) {
|
||||
int no_display = !any_display;
|
||||
any_display = 1;
|
||||
if (no_display && errmsgs > 0) {
|
||||
/*
|
||||
* We displayed some messages on error output
|
||||
* (file descriptor 2; see error() function).
|
||||
* Before erasing the screen contents,
|
||||
* display the file name and wait for a keystroke.
|
||||
*/
|
||||
error(filename);
|
||||
}
|
||||
/*
|
||||
* Indicate there is nothing displayed yet.
|
||||
*/
|
||||
if (initial_pos != NULL_POSITION)
|
||||
jump_loc(initial_pos);
|
||||
clr_linenum();
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Edit the next file in the command line list.
|
||||
*/
|
||||
next_file(n)
|
||||
int n;
|
||||
{
|
||||
extern int quit_at_eof;
|
||||
off_t position();
|
||||
|
||||
if (curr_ac + n >= ac) {
|
||||
if (quit_at_eof || position(TOP) == NULL_POSITION)
|
||||
quit();
|
||||
error("No (N-th) next file");
|
||||
}
|
||||
else
|
||||
(void)edit(av[curr_ac += n]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Edit the previous file in the command line list.
|
||||
*/
|
||||
prev_file(n)
|
||||
int n;
|
||||
{
|
||||
if (curr_ac - n < 0)
|
||||
error("No (N-th) previous file");
|
||||
else
|
||||
(void)edit(av[curr_ac -= n]);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy a file directly to standard output; used if stdout is not a tty.
|
||||
* the only processing is to squeeze multiple blank input lines.
|
||||
*/
|
||||
static
|
||||
cat_file()
|
||||
{
|
||||
extern int squeeze;
|
||||
register int c, empty;
|
||||
|
||||
if (squeeze) {
|
||||
empty = 0;
|
||||
while ((c = ch_forw_get()) != EOI)
|
||||
if (c != '\n') {
|
||||
putchr(c);
|
||||
empty = 0;
|
||||
}
|
||||
else if (empty < 2) {
|
||||
putchr(c);
|
||||
++empty;
|
||||
}
|
||||
}
|
||||
else while ((c = ch_forw_get()) != EOI)
|
||||
putchr(c);
|
||||
flush();
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int envargc, argcnt;
|
||||
char *envargv[2], *getenv();
|
||||
|
||||
/*
|
||||
* Process command line arguments and MORE environment arguments.
|
||||
* Command line arguments override environment arguments.
|
||||
*/
|
||||
if (envargv[1] = getenv("MORE")) {
|
||||
envargc = 2;
|
||||
envargv[0] = "more";
|
||||
envargv[2] = NULL;
|
||||
(void)option(envargc, envargv);
|
||||
}
|
||||
argcnt = option(argc, argv);
|
||||
argv += argcnt;
|
||||
argc -= argcnt;
|
||||
|
||||
/*
|
||||
* Set up list of files to be examined.
|
||||
*/
|
||||
ac = argc;
|
||||
av = argv;
|
||||
curr_ac = 0;
|
||||
|
||||
/*
|
||||
* Set up terminal, etc.
|
||||
*/
|
||||
is_tty = isatty(1);
|
||||
if (!is_tty) {
|
||||
/*
|
||||
* Output is not a tty.
|
||||
* Just copy the input file(s) to output.
|
||||
*/
|
||||
if (ac < 1) {
|
||||
(void)edit("-");
|
||||
cat_file();
|
||||
} else {
|
||||
do {
|
||||
(void)edit((char *)NULL);
|
||||
if (file >= 0)
|
||||
cat_file();
|
||||
} while (++curr_ac < ac);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
raw_mode(1);
|
||||
get_term();
|
||||
open_getchr();
|
||||
init();
|
||||
init_signals(1);
|
||||
|
||||
/* select the first file to examine. */
|
||||
if (tagoption) {
|
||||
/*
|
||||
* A -t option was given; edit the file selected by the
|
||||
* "tags" search, and search for the proper line in the file.
|
||||
*/
|
||||
if (!tagfile || !edit(tagfile) || tagsearch())
|
||||
quit();
|
||||
}
|
||||
else if (ac < 1)
|
||||
(void)edit("-"); /* Standard input */
|
||||
else {
|
||||
/*
|
||||
* Try all the files named as command arguments.
|
||||
* We are simply looking for one which can be
|
||||
* opened without error.
|
||||
*/
|
||||
do {
|
||||
(void)edit((char *)NULL);
|
||||
} while (file < 0 && ++curr_ac < ac);
|
||||
}
|
||||
|
||||
if (file >= 0)
|
||||
commands();
|
||||
quit();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a string to a "safe" place
|
||||
* (that is, to a buffer allocated by malloc).
|
||||
*/
|
||||
char *
|
||||
save(s)
|
||||
char *s;
|
||||
{
|
||||
char *p, *strcpy(), *malloc();
|
||||
|
||||
p = malloc((u_int)strlen(s)+1);
|
||||
if (p == NULL)
|
||||
{
|
||||
error("cannot allocate memory");
|
||||
quit();
|
||||
}
|
||||
return(strcpy(p, s));
|
||||
}
|
||||
|
||||
/*
|
||||
* Exit the program.
|
||||
*/
|
||||
quit()
|
||||
{
|
||||
/*
|
||||
* Put cursor at bottom left corner, clear the line,
|
||||
* reset the terminal modes, and exit.
|
||||
*/
|
||||
quitting = 1;
|
||||
lower_left();
|
||||
clear_eol();
|
||||
deinit();
|
||||
flush();
|
||||
raw_mode(0);
|
||||
exit(0);
|
||||
}
|
@ -1,316 +0,0 @@
|
||||
.\" Copyright (c) 1988, 1990 The Regents of the University of California.
|
||||
.\" Copyright (c) 1988 Mark Nudleman
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from: @(#)more.1 5.15 (Berkeley) 7/29/91
|
||||
.\" $Id: more.1,v 1.6 1995/08/06 09:22:36 ghudson Exp $
|
||||
.\"
|
||||
.Dd July 29, 1991
|
||||
.Dt MORE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm more
|
||||
.Nd file perusal filter for crt viewing
|
||||
.Sh SYNOPSIS
|
||||
.Nm more
|
||||
.Op Fl ceinus
|
||||
.Op Fl t Ar tag
|
||||
.Op Fl x Ar tabs
|
||||
.Op Fl / Ar pattern
|
||||
.Op Fl #
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
.Nm More
|
||||
is a filter for paging through text one screenful at a time. It
|
||||
uses
|
||||
.Xr termcap 3
|
||||
so it can run on a variety of terminals. There is even limited support
|
||||
for hardcopy terminals. (On a hardcopy terminal, lines which should be
|
||||
printed at the top of the screen are prefixed with an up-arrow.)
|
||||
.Ar File
|
||||
may be a single dash (``-''), implying stdin.
|
||||
.Sh OPTIONS
|
||||
Command line options are described below.
|
||||
Options are also taken from the environment variable
|
||||
.Ev MORE
|
||||
(make sure to precede them with a dash (``-'')) but command
|
||||
line options will override them.
|
||||
.Bl -tag -width flag
|
||||
.It Fl c
|
||||
Normally,
|
||||
.Nm more
|
||||
will repaint the screen by scrolling from the bottom of the screen.
|
||||
If the
|
||||
.Fl c
|
||||
option is set, when
|
||||
.Nm more
|
||||
needs to change the entire display, it will paint from the top line down.
|
||||
.It Fl d
|
||||
The
|
||||
.Fl d
|
||||
option causes the default prompt to include the basic directions
|
||||
``[Press space to continue, 'q' to quit.]''. The
|
||||
.Fl d
|
||||
option also causes the message ``[Press 'h' for instructions.]'' to be
|
||||
displayed when an invalid command is entered (normally, the bell is
|
||||
rung). This option is useful in environments where users may not be
|
||||
experienced with pagers.
|
||||
.It Fl e
|
||||
Normally, if displaying a single file,
|
||||
.Nm more
|
||||
exits as soon as it reaches end-of-file. The
|
||||
.Fl e
|
||||
option tells more to
|
||||
exit if it reaches end-of-file twice without an intervening operation.
|
||||
If the file is shorter than a single screen
|
||||
.Nm more
|
||||
will exit at end-of-file regardless.
|
||||
.It Fl i
|
||||
The
|
||||
.Fl i
|
||||
option causes searches to ignore case; that is,
|
||||
uppercase and lowercase are considered identical.
|
||||
.It Fl n
|
||||
The
|
||||
.Fl n
|
||||
flag suppresses line numbers.
|
||||
The default (to use line numbers) may cause
|
||||
.Nm more
|
||||
to run more slowly in some cases, especially with a very large input file.
|
||||
Suppressing line numbers with the
|
||||
.Fl n
|
||||
flag will avoid this problem.
|
||||
Using line numbers means: the line number will be displayed in the
|
||||
.Cm =
|
||||
command, and the
|
||||
.Cm v
|
||||
command will pass the current line number to the editor.
|
||||
.It Fl s
|
||||
The
|
||||
.Fl s
|
||||
option causes
|
||||
consecutive blank lines to be squeezed into a single blank line.
|
||||
.It Fl t
|
||||
The
|
||||
.Fl t
|
||||
option, followed immediately by a tag, will edit the file
|
||||
containing that tag. For more information, see the
|
||||
.Xr ctags 1
|
||||
command.
|
||||
.It Fl u
|
||||
By default,
|
||||
.Nm more
|
||||
treats backspaces and
|
||||
.Dv CR-LF
|
||||
sequences specially. Backspaces which appear
|
||||
adjacent to an underscore character are displayed as underlined text.
|
||||
Backspaces which appear between two identical characters are displayed
|
||||
as emboldened text.
|
||||
.Dv CR-LF
|
||||
sequences are compressed to a single linefeed
|
||||
character. The
|
||||
.Fl u
|
||||
option causes backspaces to always be displayed as
|
||||
control characters, i.e. as the two character sequence ``^H'', and
|
||||
.Dv CR-LF
|
||||
to be left alone.
|
||||
.It Fl x
|
||||
The
|
||||
.Fl x
|
||||
option sets tab stops every
|
||||
.Ar N
|
||||
positions. The default for
|
||||
.Ar N
|
||||
is 8.
|
||||
.It Fl /
|
||||
The
|
||||
.Fl /
|
||||
option specifies a string that will be searched for before
|
||||
each file is displayed.
|
||||
.Sh COMMANDS
|
||||
Interactive commands for
|
||||
.Nm more
|
||||
are based on
|
||||
.Xr vi 1 .
|
||||
Some commands may be preceeded by a decimal number, called N in the
|
||||
descriptions below.
|
||||
In the following descriptions, ^X means control-X.
|
||||
.Pp
|
||||
.Bl -tag -width Ic
|
||||
.It Ic h
|
||||
Help: display a summary of these commands.
|
||||
If you forget all the other commands, remember this one.
|
||||
.It Xo
|
||||
.Ic SPACE
|
||||
.No or
|
||||
.Ic f
|
||||
.No or
|
||||
.Ic \&^F
|
||||
.Xc
|
||||
Scroll forward N lines, default one window.
|
||||
If N is more than the screen size, only the final screenful is displayed.
|
||||
.It Ic b No or Ic \&^B
|
||||
Scroll backward N lines, default one window (see option -z below).
|
||||
If N is more than the screen size, only the final screenful is displayed.
|
||||
.It Ic j No or Ic RETURN
|
||||
Scroll forward N lines, default 1.
|
||||
The entire N lines are displayed, even if N is more than the screen size.
|
||||
.It Ic k
|
||||
Scroll backward N lines, default 1.
|
||||
The entire N lines are displayed, even if N is more than the screen size.
|
||||
.It Ic d No or Ic \&^D
|
||||
Scroll forward N lines, default one half of the screen size.
|
||||
If N is specified, it becomes the new default for
|
||||
subsequent d and u commands.
|
||||
.It Ic u No or Ic \&^U
|
||||
Scroll backward N lines, default one half of the screen size.
|
||||
If N is specified, it becomes the new default for
|
||||
subsequent d and u commands.
|
||||
.It Ic g
|
||||
Go to line N in the file, default 1 (beginning of file).
|
||||
.It Ic G
|
||||
Go to line N in the file, default the end of the file.
|
||||
.It Ic p No or Ic \&%
|
||||
Go to a position N percent into the file. N should be between 0
|
||||
and 100. (This works if standard input is being read, but only if
|
||||
.Nm more
|
||||
has already read to the end of the file. It is always fast, but
|
||||
not always useful.)
|
||||
.It Ic r No or Ic \&^L
|
||||
Repaint the screen.
|
||||
.It Ic R
|
||||
Repaint the screen, discarding any buffered input.
|
||||
Useful if the file is changing while it is being viewed.
|
||||
.It Ic m
|
||||
Followed by any lowercase letter,
|
||||
marks the current position with that letter.
|
||||
.It Ic \&'
|
||||
(Single quote.)
|
||||
Followed by any lowercase letter, returns to the position which
|
||||
was previously marked with that letter.
|
||||
Followed by another single quote, returns to the position at
|
||||
which the last "large" movement command was executed, or the
|
||||
beginning of the file if no such movements have occurred.
|
||||
All marks are lost when a new file is examined.
|
||||
.It Ic \&! Ns Ar command
|
||||
Invoke a shell command. The characters `%', `#', and `!'
|
||||
are replaced by the current file name, previous filename
|
||||
and previous shell command, respectively. If there is no
|
||||
current or previous filename, `%' and `#' are not expanded.
|
||||
`\%' `\#' and `\!' are replaced by `%', `#' and `!',
|
||||
respectively.
|
||||
.It Ic \&/ Ns Ar pattern
|
||||
Search forward in the file for the N-th line containing the pattern.
|
||||
N defaults to 1.
|
||||
The pattern is a regular expression, as recognized by
|
||||
.Xr ed .
|
||||
The search starts at the second line displayed.
|
||||
.It Ic \&? Ns Ar pattern
|
||||
Search backward in the file for the N-th line containing the pattern.
|
||||
The search starts at the line immediately before the top line displayed.
|
||||
.It Ic \&/\&! Ns Ar pattern
|
||||
Like /, but the search is for the N-th line
|
||||
which does NOT contain the pattern.
|
||||
.It Ic \&?\&! Ns Ar pattern
|
||||
Like ?, but the search is for the N-th line
|
||||
which does NOT contain the pattern.
|
||||
.It Ic n
|
||||
Repeat previous search, for N-th line containing the last pattern
|
||||
(or
|
||||
.Tn NOT
|
||||
containing the last pattern, if the previous search
|
||||
was /! or ?!).
|
||||
.It Ic E Ns Op Ar filename
|
||||
Examine a new file.
|
||||
If the filename is missing, the "current" file (see the N and P commands
|
||||
below) from the list of files in the command line is re-examined.
|
||||
If the filename is a pound sign (#), the previously examined file is
|
||||
re-examined.
|
||||
.It Ic N No or Ic \&:n
|
||||
Examine the next file (from the list of files given in the command line).
|
||||
If a number N is specified (not to be confused with the command N),
|
||||
the N-th next file is examined.
|
||||
.It Ic P No or Ic \&:p
|
||||
Examine the previous file.
|
||||
If a number N is specified, the N-th previous file is examined.
|
||||
.It Ic \&:t
|
||||
Go to supplied tag.
|
||||
.It Ic v
|
||||
Invokes an editor to edit the current file being viewed.
|
||||
The editor is taken from the environment variable
|
||||
.Ev EDITOR ,
|
||||
or defaults to
|
||||
.Xr vi 1 .
|
||||
.It Ic \&= No or Ic \&^G
|
||||
These options print out the number of the file currently being displayed
|
||||
relative to the total number of files there are to display, the current
|
||||
line number, the current byte number and the total bytes to display, and
|
||||
what percentage of the file has been displayed. If
|
||||
.Nm more
|
||||
is reading from stdin, or the file is shorter than a single screen, some
|
||||
of these items may not be available. Note, all of these items reference
|
||||
the first byte of the last line displayed on the screen.
|
||||
.It Xo
|
||||
.Ic q
|
||||
.No or
|
||||
.Ic \&:q
|
||||
.No or
|
||||
.Ic ZZ
|
||||
.Xc
|
||||
Exits
|
||||
.Nm more .
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
.Nm More
|
||||
utilizes the following environment variables, if they exist:
|
||||
.Bl -tag -width Fl
|
||||
.It Ev MORE
|
||||
This variable may be set with favored options to
|
||||
.Nm more .
|
||||
.It Ev EDITOR
|
||||
Specify default editor.
|
||||
.It Ev SHELL
|
||||
Current shell in use (normally set by the shell at login time).
|
||||
.It Ev TERM
|
||||
Specifies terminal type, used by more to get the terminal
|
||||
characteristics necessary to manipulate the screen.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr ctags 1 ,
|
||||
.Xr vi 1
|
||||
.Sh AUTHOR
|
||||
This software is derived from software contributed to Berkeley
|
||||
by Mark Nudleman.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm more
|
||||
command appeared in
|
||||
.Bx 3.0 .
|
@ -1,41 +0,0 @@
|
||||
Commands flagged with an asterisk (``*'') may be preceeded by a number.
|
||||
Commands of the form ``^X'' are control characters, i.e. control-X.
|
||||
|
||||
h Display this help.
|
||||
|
||||
f, ^F, SPACE * Forward N lines, default one screen.
|
||||
b, ^B * Backward N lines, default one screen.
|
||||
j, CR * Forward N lines, default 1 line.
|
||||
k * Backward N lines, default 1 line.
|
||||
d, ^D * Forward N lines, default half screen or last N to d/u.
|
||||
u, ^U * Backward N lines, default half screen or last N to d/u.
|
||||
g * Go to line N, default 1.
|
||||
G * Go to line N, default the end of the file.
|
||||
p, % * Position to N percent into the file.
|
||||
|
||||
r, ^L Repaint screen.
|
||||
R Repaint screen, discarding buffered input.
|
||||
|
||||
m[a-z] Mark the current position with the supplied letter.
|
||||
'[a-z] Return to the position previously marked by this letter.
|
||||
'' Return to previous position.
|
||||
|
||||
/pattern * Search forward for N-th line containing the pattern.
|
||||
/!pattern * Search forward for N-th line NOT containing the pattern.
|
||||
?pattern * Search backward for N-th line containing the pattern.
|
||||
?!pattern * Search backward for N-th line NOT containing the pattern.
|
||||
n * Repeat previous search (for N-th occurence).
|
||||
|
||||
!command Execute command in a subshell.
|
||||
:!command Execute command in a subshell.
|
||||
:a Display the list of files.
|
||||
E [file] Examine a new file.
|
||||
:n, N * Examine the next file.
|
||||
:p, P * Examine the previous file.
|
||||
:t [tag] Examine the tag.
|
||||
v Run an editor on the current file.
|
||||
|
||||
=, ^G Print current file name and stats.
|
||||
|
||||
q, :q, or ZZ Exit.
|
||||
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)option.c 5.11 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: option.c,v 1.3 1995/08/06 09:22:34 ghudson Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <less.h>
|
||||
|
||||
int top_scroll; /* Repaint screen from top */
|
||||
int bs_mode; /* How to process backspaces */
|
||||
int caseless; /* Do "caseless" searches */
|
||||
int cbufs = 10; /* Current number of buffers */
|
||||
int linenums = 1; /* Use line numbers */
|
||||
int quit_at_eof;
|
||||
int squeeze; /* Squeeze multiple blank lines into one */
|
||||
int tabstop = 8; /* Tab settings */
|
||||
int tagoption;
|
||||
int novice = 0;
|
||||
|
||||
char *firstsearch;
|
||||
extern int sc_height;
|
||||
|
||||
option(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
static int sc_window_set = 0;
|
||||
int ch;
|
||||
char *p;
|
||||
|
||||
/* backward compatible processing for "+/search" */
|
||||
char **a;
|
||||
for (a = argv; *a; ++a)
|
||||
if ((*a)[0] == '+' && (*a)[1] == '/')
|
||||
(*a)[0] = '-';
|
||||
|
||||
optind = 1; /* called twice, re-init getopt. */
|
||||
while ((ch = getopt(argc, argv, "0123456789/:cdeinst:ux:f")) != EOF)
|
||||
switch((char)ch) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
/*
|
||||
* kludge: more was originally designed to take
|
||||
* a number after a dash.
|
||||
*/
|
||||
if (!sc_window_set) {
|
||||
p = argv[optind - 1];
|
||||
if (p[0] == '-' && p[1] == ch && !p[2])
|
||||
sc_height = atoi(++p);
|
||||
else
|
||||
sc_height = atoi(argv[optind] + 1);
|
||||
sc_window_set = 1;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
firstsearch = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
top_scroll = 1;
|
||||
break;
|
||||
case 'd':
|
||||
novice = 1;
|
||||
break;
|
||||
case 'e':
|
||||
quit_at_eof = 1;
|
||||
break;
|
||||
case 'i':
|
||||
caseless = 1;
|
||||
break;
|
||||
case 'n':
|
||||
linenums = 0;
|
||||
break;
|
||||
case 's':
|
||||
squeeze = 1;
|
||||
break;
|
||||
case 't':
|
||||
tagoption = 1;
|
||||
findtag(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
bs_mode = 1;
|
||||
break;
|
||||
case 'x':
|
||||
tabstop = atoi(optarg);
|
||||
if (tabstop <= 0)
|
||||
tabstop = 8;
|
||||
break;
|
||||
case 'f': /* ignore -f, compatability with old more */
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"usage: more [-ceinus] [-t tag] [-x tabs] [-/ pattern] [-#] [file ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
return(optind);
|
||||
}
|
@ -1,285 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)os.c 5.12 (Berkeley) 3/1/91"; */
|
||||
static char *rcsid = "$Id: os.c,v 1.3 1994/12/24 17:17:10 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Operating system dependent routines.
|
||||
*
|
||||
* Most of the stuff in here is based on Unix, but an attempt
|
||||
* has been made to make things work on other operating systems.
|
||||
* This will sometimes result in a loss of functionality, unless
|
||||
* someone rewrites code specifically for the new operating system.
|
||||
*
|
||||
* The makefile provides defines to decide whether various
|
||||
* Unix features are present.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <less.h>
|
||||
#include "pathnames.h"
|
||||
|
||||
int reading;
|
||||
|
||||
extern int screen_trashed;
|
||||
|
||||
static jmp_buf read_label;
|
||||
|
||||
/*
|
||||
* Pass the specified command to a shell to be executed.
|
||||
* Like plain "system()", but handles resetting terminal modes, etc.
|
||||
*/
|
||||
lsystem(cmd)
|
||||
char *cmd;
|
||||
{
|
||||
int inp;
|
||||
char cmdbuf[256];
|
||||
char *shell, *getenv();
|
||||
|
||||
/*
|
||||
* Print the command which is to be executed,
|
||||
* unless the command starts with a "-".
|
||||
*/
|
||||
if (cmd[0] == '-')
|
||||
cmd++;
|
||||
else
|
||||
{
|
||||
lower_left();
|
||||
clear_eol();
|
||||
putstr("!");
|
||||
putstr(cmd);
|
||||
putstr("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* De-initialize the terminal and take out of raw mode.
|
||||
*/
|
||||
deinit();
|
||||
flush();
|
||||
raw_mode(0);
|
||||
|
||||
/*
|
||||
* Restore signals to their defaults.
|
||||
*/
|
||||
init_signals(0);
|
||||
|
||||
/*
|
||||
* Force standard input to be the terminal, "/dev/tty",
|
||||
* even if less's standard input is coming from a pipe.
|
||||
*/
|
||||
inp = dup(0);
|
||||
(void)close(0);
|
||||
if (open(_PATH_TTY, O_RDONLY, 0) < 0)
|
||||
(void)dup(inp);
|
||||
|
||||
/*
|
||||
* Pass the command to the system to be executed.
|
||||
* If we have a SHELL environment variable, use
|
||||
* <$SHELL -c "command"> instead of just <command>.
|
||||
* If the command is empty, just invoke a shell.
|
||||
*/
|
||||
if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
|
||||
{
|
||||
if (*cmd == '\0')
|
||||
cmd = shell;
|
||||
else
|
||||
{
|
||||
(void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
|
||||
cmd = cmdbuf;
|
||||
}
|
||||
}
|
||||
if (*cmd == '\0')
|
||||
cmd = "sh";
|
||||
|
||||
(void)system(cmd);
|
||||
|
||||
/*
|
||||
* Restore standard input, reset signals, raw mode, etc.
|
||||
*/
|
||||
(void)close(0);
|
||||
(void)dup(inp);
|
||||
(void)close(inp);
|
||||
|
||||
init_signals(1);
|
||||
raw_mode(1);
|
||||
init();
|
||||
screen_trashed = 1;
|
||||
#if defined(SIGWINCH) || defined(SIGWIND)
|
||||
/*
|
||||
* Since we were ignoring window change signals while we executed
|
||||
* the system command, we must assume the window changed.
|
||||
*/
|
||||
winch();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Like read() system call, but is deliberately interruptable.
|
||||
* A call to intread() from a signal handler will interrupt
|
||||
* any pending iread().
|
||||
*/
|
||||
iread(fd, buf, len)
|
||||
int fd;
|
||||
char *buf;
|
||||
int len;
|
||||
{
|
||||
register int n;
|
||||
|
||||
if (setjmp(read_label))
|
||||
/*
|
||||
* We jumped here from intread.
|
||||
*/
|
||||
return (READ_INTR);
|
||||
|
||||
flush();
|
||||
reading = 1;
|
||||
n = read(fd, buf, len);
|
||||
reading = 0;
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
return (n);
|
||||
}
|
||||
|
||||
intread()
|
||||
{
|
||||
(void)sigsetmask(0L);
|
||||
longjmp(read_label, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand a filename, substituting any environment variables, etc.
|
||||
* The implementation of this is necessarily very operating system
|
||||
* dependent. This implementation is unabashedly only for Unix systems.
|
||||
*/
|
||||
FILE *popen();
|
||||
|
||||
char *
|
||||
glob(filename)
|
||||
char *filename;
|
||||
{
|
||||
FILE *f;
|
||||
char *p;
|
||||
int ch;
|
||||
char *cmd, *malloc(), *getenv();
|
||||
static char buffer[MAXPATHLEN];
|
||||
|
||||
if (filename[0] == '#')
|
||||
return (filename);
|
||||
|
||||
/*
|
||||
* We get the shell to expand the filename for us by passing
|
||||
* an "echo" command to the shell and reading its output.
|
||||
*/
|
||||
p = getenv("SHELL");
|
||||
if (p == NULL || *p == '\0')
|
||||
{
|
||||
/*
|
||||
* Read the output of <echo filename>.
|
||||
*/
|
||||
cmd = malloc((u_int)(strlen(filename)+8));
|
||||
if (cmd == NULL)
|
||||
return (filename);
|
||||
(void)sprintf(cmd, "echo \"%s\"", filename);
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Read the output of <$SHELL -c "echo filename">.
|
||||
*/
|
||||
cmd = malloc((u_int)(strlen(p)+12));
|
||||
if (cmd == NULL)
|
||||
return (filename);
|
||||
(void)sprintf(cmd, "%s -c \"echo %s\"", p, filename);
|
||||
}
|
||||
|
||||
if ((f = popen(cmd, "r")) == NULL)
|
||||
return (filename);
|
||||
free(cmd);
|
||||
|
||||
for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++)
|
||||
{
|
||||
if ((ch = getc(f)) == '\n' || ch == EOF)
|
||||
break;
|
||||
*p = ch;
|
||||
}
|
||||
*p = '\0';
|
||||
(void)pclose(f);
|
||||
return(buffer);
|
||||
}
|
||||
|
||||
char *
|
||||
bad_file(filename, message, len)
|
||||
char *filename, *message;
|
||||
u_int len;
|
||||
{
|
||||
extern int errno;
|
||||
struct stat statbuf;
|
||||
char *strcat(), *strerror();
|
||||
|
||||
if (stat(filename, &statbuf) < 0) {
|
||||
(void)sprintf(message, "%s: %s", filename, strerror(errno));
|
||||
return(message);
|
||||
}
|
||||
if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
|
||||
static char is_dir[] = " is a directory";
|
||||
|
||||
strtcpy(message, filename, (int)(len-sizeof(is_dir)-1));
|
||||
(void)strcat(message, is_dir);
|
||||
return(message);
|
||||
}
|
||||
return((char *)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a string, truncating to the specified length if necessary.
|
||||
* Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
|
||||
*/
|
||||
strtcpy(to, from, len)
|
||||
char *to, *from;
|
||||
int len;
|
||||
{
|
||||
char *strncpy();
|
||||
|
||||
(void)strncpy(to, from, (int)len);
|
||||
to[len-1] = '\0';
|
||||
}
|
||||
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)output.c 5.10 (Berkeley) 7/24/91"; */
|
||||
static char *rcsid = "$Id: output.c,v 1.4 1994/12/24 17:17:11 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* High level routines dealing with the output to the screen.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <less.h>
|
||||
|
||||
int errmsgs; /* Count of messages displayed by error() */
|
||||
|
||||
extern int sigs;
|
||||
extern int sc_width, sc_height;
|
||||
extern int ul_width, ue_width;
|
||||
extern int so_width, se_width;
|
||||
extern int bo_width, be_width;
|
||||
extern int tabstop;
|
||||
extern int screen_trashed;
|
||||
extern int any_display;
|
||||
extern char *line;
|
||||
|
||||
/* display the line which is in the line buffer. */
|
||||
put_line()
|
||||
{
|
||||
register char *p;
|
||||
register int c;
|
||||
register int column;
|
||||
extern int auto_wrap, ignaw;
|
||||
|
||||
if (sigs)
|
||||
{
|
||||
/*
|
||||
* Don't output if a signal is pending.
|
||||
*/
|
||||
screen_trashed = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line == NULL)
|
||||
line = "";
|
||||
|
||||
column = 0;
|
||||
for (p = line; *p != '\0'; p++)
|
||||
{
|
||||
switch (c = *p)
|
||||
{
|
||||
case UL_CHAR:
|
||||
ul_enter();
|
||||
column += ul_width; /* +1; XXX */
|
||||
break;
|
||||
case UE_CHAR:
|
||||
ul_exit();
|
||||
column += ue_width;
|
||||
break;
|
||||
case BO_CHAR:
|
||||
bo_enter();
|
||||
column += bo_width; /* +1; XXX */
|
||||
break;
|
||||
case BE_CHAR:
|
||||
bo_exit();
|
||||
column += be_width;
|
||||
break;
|
||||
case '\t':
|
||||
do
|
||||
{
|
||||
putchr(' ');
|
||||
column++;
|
||||
} while ((column % tabstop) != 0);
|
||||
break;
|
||||
case '\b':
|
||||
putbs();
|
||||
column--;
|
||||
break;
|
||||
default:
|
||||
if (c & 0200)
|
||||
{
|
||||
/*
|
||||
* Control characters arrive here as the
|
||||
* normal character [CARAT_CHAR(c)] with
|
||||
* the 0200 bit set. See pappend().
|
||||
*/
|
||||
putchr('^');
|
||||
putchr(c & 0177);
|
||||
column += 2;
|
||||
} else
|
||||
{
|
||||
putchr(c);
|
||||
column++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (column < sc_width || !auto_wrap || ignaw)
|
||||
putchr('\n');
|
||||
}
|
||||
|
||||
static char obuf[1024];
|
||||
static char *ob = obuf;
|
||||
|
||||
/*
|
||||
* Flush buffered output.
|
||||
*/
|
||||
flush()
|
||||
{
|
||||
register int n;
|
||||
|
||||
n = ob - obuf;
|
||||
if (n == 0)
|
||||
return;
|
||||
if (write(1, obuf, n) != n)
|
||||
screen_trashed = 1;
|
||||
ob = obuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Purge any pending output.
|
||||
*/
|
||||
purge()
|
||||
{
|
||||
|
||||
ob = obuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a character.
|
||||
*/
|
||||
putchr(c)
|
||||
int c;
|
||||
{
|
||||
if (ob >= &obuf[sizeof(obuf)])
|
||||
flush();
|
||||
*ob++ = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a string.
|
||||
*/
|
||||
putstr(s)
|
||||
register char *s;
|
||||
{
|
||||
while (*s != '\0')
|
||||
putchr(*s++);
|
||||
}
|
||||
|
||||
int cmdstack;
|
||||
static char return_to_continue[] = "(press RETURN)";
|
||||
|
||||
/*
|
||||
* Output a message in the lower left corner of the screen
|
||||
* and wait for carriage return.
|
||||
*/
|
||||
error(s)
|
||||
char *s;
|
||||
{
|
||||
int ch;
|
||||
|
||||
++errmsgs;
|
||||
if (!any_display) {
|
||||
/*
|
||||
* Nothing has been displayed yet. Output this message on
|
||||
* error output (file descriptor 2) and don't wait for a
|
||||
* keystroke to continue.
|
||||
*
|
||||
* This has the desirable effect of producing all error
|
||||
* messages on error output if standard output is directed
|
||||
* to a file. It also does the same if we never produce
|
||||
* any real output; for example, if the input file(s) cannot
|
||||
* be opened. If we do eventually produce output, code in
|
||||
* edit() makes sure these messages can be seen before they
|
||||
* are overwritten or scrolled away.
|
||||
*/
|
||||
if (s != NULL) {
|
||||
(void)write(2, s, strlen(s));
|
||||
(void)write(2, "\n", 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
lower_left();
|
||||
clear_eol();
|
||||
so_enter();
|
||||
if (s != NULL) {
|
||||
putstr(s);
|
||||
putstr(" ");
|
||||
}
|
||||
putstr(return_to_continue);
|
||||
so_exit();
|
||||
|
||||
if ((ch = getchr()) != '\n') {
|
||||
if (ch == 'q')
|
||||
quit();
|
||||
cmdstack = ch;
|
||||
}
|
||||
lower_left();
|
||||
|
||||
if ((s != NULL ? strlen(s) : 0) + sizeof(return_to_continue) +
|
||||
so_width + se_width + 1 > sc_width)
|
||||
/*
|
||||
* Printing the message has probably scrolled the screen.
|
||||
* {{ Unless the terminal doesn't have auto margins,
|
||||
* in which case we just hammered on the right margin. }}
|
||||
*/
|
||||
/* repaint(); */
|
||||
screen_trashed = 1; /* XXX */
|
||||
flush();
|
||||
}
|
||||
|
||||
static char intr_to_abort[] = "... (interrupt to abort)";
|
||||
|
||||
ierror(s)
|
||||
char *s;
|
||||
{
|
||||
lower_left();
|
||||
clear_eol();
|
||||
so_enter();
|
||||
putstr(s);
|
||||
putstr(intr_to_abort);
|
||||
so_exit();
|
||||
flush();
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1989 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)pathnames.h 5.2 (Berkeley) 6/1/90
|
||||
* $Id: pathnames.h,v 1.4 1993/11/09 05:12:17 cgd Exp $
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_HELPFILE "/usr/share/misc/more.help"
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)position.c 5.7 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: position.c,v 1.2 1993/11/09 05:12:29 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines dealing with the "position" table.
|
||||
* This is a table which tells the position (in the input file) of the
|
||||
* first char on each currently displayed line.
|
||||
*
|
||||
* {{ The position table is scrolled by moving all the entries.
|
||||
* Would be better to have a circular table
|
||||
* and just change a couple of pointers. }}
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <less.h>
|
||||
|
||||
static off_t *table; /* The position table */
|
||||
static int tablesize;
|
||||
|
||||
extern int sc_height;
|
||||
|
||||
/*
|
||||
* Return the starting file position of a line displayed on the screen.
|
||||
* The line may be specified as a line number relative to the top
|
||||
* of the screen, but is usually one of these special cases:
|
||||
* the top (first) line on the screen
|
||||
* the second line on the screen
|
||||
* the bottom line on the screen
|
||||
* the line after the bottom line on the screen
|
||||
*/
|
||||
off_t
|
||||
position(where)
|
||||
int where;
|
||||
{
|
||||
switch (where)
|
||||
{
|
||||
case BOTTOM:
|
||||
where = sc_height - 2;
|
||||
break;
|
||||
case BOTTOM_PLUS_ONE:
|
||||
where = sc_height - 1;
|
||||
break;
|
||||
case MIDDLE:
|
||||
where = sc_height / 2;
|
||||
}
|
||||
return (table[where]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new file position to the bottom of the position table.
|
||||
*/
|
||||
add_forw_pos(pos)
|
||||
off_t pos;
|
||||
{
|
||||
register int i;
|
||||
|
||||
/*
|
||||
* Scroll the position table up.
|
||||
*/
|
||||
for (i = 1; i < sc_height; i++)
|
||||
table[i-1] = table[i];
|
||||
table[sc_height - 1] = pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new file position to the top of the position table.
|
||||
*/
|
||||
add_back_pos(pos)
|
||||
off_t pos;
|
||||
{
|
||||
register int i;
|
||||
|
||||
/*
|
||||
* Scroll the position table down.
|
||||
*/
|
||||
for (i = sc_height - 1; i > 0; i--)
|
||||
table[i] = table[i-1];
|
||||
table[0] = pos;
|
||||
}
|
||||
|
||||
copytable()
|
||||
{
|
||||
register int a, b;
|
||||
|
||||
for (a = 0; a < sc_height && table[a] == NULL_POSITION; a++);
|
||||
for (b = 0; a < sc_height; a++, b++) {
|
||||
table[b] = table[a];
|
||||
table[a] = NULL_POSITION;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the position table, done whenever we clear the screen.
|
||||
*/
|
||||
pos_clear()
|
||||
{
|
||||
register int i;
|
||||
extern char *malloc(), *realloc();
|
||||
|
||||
if (table == 0) {
|
||||
tablesize = sc_height > 25 ? sc_height : 25;
|
||||
table = (off_t *)malloc(tablesize * sizeof *table);
|
||||
} else if (sc_height >= tablesize) {
|
||||
tablesize = sc_height;
|
||||
table = (off_t *)realloc(table, tablesize * sizeof *table);
|
||||
}
|
||||
|
||||
for (i = 0; i < sc_height; i++)
|
||||
table[i] = NULL_POSITION;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the byte at a specified position is currently on the screen.
|
||||
* Check the position table to see if the position falls within its range.
|
||||
* Return the position table entry if found, -1 if not.
|
||||
*/
|
||||
onscreen(pos)
|
||||
off_t pos;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (pos < table[0])
|
||||
return (-1);
|
||||
for (i = 1; i < sc_height; i++)
|
||||
if (pos < table[i])
|
||||
return (i-1);
|
||||
return (-1);
|
||||
}
|
@ -1,873 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)prim.c 5.8 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: prim.c,v 1.4 1994/12/24 17:17:12 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Primitives for displaying the file on the screen.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <less.h>
|
||||
|
||||
#ifdef REGEX
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
int back_scroll = -1;
|
||||
int hit_eof; /* keeps track of how many times we hit end of file */
|
||||
int screen_trashed;
|
||||
|
||||
static int squished;
|
||||
|
||||
extern int sigs;
|
||||
extern int top_scroll;
|
||||
extern int sc_width, sc_height;
|
||||
extern int caseless;
|
||||
extern int linenums;
|
||||
extern int tagoption;
|
||||
extern char *line;
|
||||
|
||||
off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line();
|
||||
off_t ch_length(), ch_tell();
|
||||
|
||||
/*
|
||||
* Check to see if the end of file is currently "displayed".
|
||||
*/
|
||||
eof_check()
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
if (sigs)
|
||||
return;
|
||||
/*
|
||||
* If the bottom line is empty, we are at EOF.
|
||||
* If the bottom line ends at the file length,
|
||||
* we must be just at EOF.
|
||||
*/
|
||||
pos = position(BOTTOM_PLUS_ONE);
|
||||
if (pos == NULL_POSITION || pos == ch_length())
|
||||
hit_eof++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the screen is "squished", repaint it.
|
||||
* "Squished" means the first displayed line is not at the top
|
||||
* of the screen; this can happen when we display a short file
|
||||
* for the first time.
|
||||
*/
|
||||
squish_check()
|
||||
{
|
||||
if (squished) {
|
||||
squished = 0;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display n lines, scrolling forward, starting at position pos in the
|
||||
* input file. "only_last" means display only the last screenful if
|
||||
* n > screen size.
|
||||
*/
|
||||
forw(n, pos, only_last)
|
||||
register int n;
|
||||
off_t pos;
|
||||
int only_last;
|
||||
{
|
||||
extern int short_file;
|
||||
static int first_time = 1;
|
||||
int eof = 0, do_repaint;
|
||||
|
||||
squish_check();
|
||||
|
||||
/*
|
||||
* do_repaint tells us not to display anything till the end,
|
||||
* then just repaint the entire screen.
|
||||
*/
|
||||
do_repaint = (only_last && n > sc_height-1);
|
||||
|
||||
if (!do_repaint) {
|
||||
if (top_scroll && n >= sc_height - 1) {
|
||||
/*
|
||||
* Start a new screen.
|
||||
* {{ This is not really desirable if we happen
|
||||
* to hit eof in the middle of this screen,
|
||||
* but we don't yet know if that will happen. }}
|
||||
*/
|
||||
clear();
|
||||
home();
|
||||
} else {
|
||||
lower_left();
|
||||
clear_eol();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is not contiguous with what is currently displayed.
|
||||
* Clear the screen image (position table) and start a new
|
||||
* screen.
|
||||
*/
|
||||
if (pos != position(BOTTOM_PLUS_ONE)) {
|
||||
pos_clear();
|
||||
add_forw_pos(pos);
|
||||
if (top_scroll) {
|
||||
clear();
|
||||
home();
|
||||
} else if (!first_time)
|
||||
putstr("...skipping...\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (short_file = 0; --n >= 0;) {
|
||||
/*
|
||||
* Read the next line of input.
|
||||
*/
|
||||
pos = forw_line(pos);
|
||||
if (pos == NULL_POSITION) {
|
||||
/*
|
||||
* end of file; copy the table if the file was
|
||||
* too small for an entire screen.
|
||||
*/
|
||||
eof = 1;
|
||||
if (position(TOP) == NULL_POSITION) {
|
||||
copytable();
|
||||
if (!position(TOP))
|
||||
short_file = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Add the position of the next line to the position table.
|
||||
* Display the current line on the screen.
|
||||
*/
|
||||
add_forw_pos(pos);
|
||||
if (do_repaint)
|
||||
continue;
|
||||
/*
|
||||
* If this is the first screen displayed and we hit an early
|
||||
* EOF (i.e. before the requested number of lines), we
|
||||
* "squish" the display down at the bottom of the screen.
|
||||
* But don't do this if a -t option was given; it can cause
|
||||
* us to start the display after the beginning of the file,
|
||||
* and it is not appropriate to squish in that case.
|
||||
*/
|
||||
if (first_time && line == NULL && !top_scroll && !tagoption) {
|
||||
squished = 1;
|
||||
continue;
|
||||
}
|
||||
put_line();
|
||||
}
|
||||
|
||||
if (eof && !sigs)
|
||||
hit_eof++;
|
||||
else
|
||||
eof_check();
|
||||
if (do_repaint)
|
||||
repaint();
|
||||
first_time = 0;
|
||||
(void) currline(BOTTOM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display n lines, scrolling backward.
|
||||
*/
|
||||
back(n, pos, only_last)
|
||||
register int n;
|
||||
off_t pos;
|
||||
int only_last;
|
||||
{
|
||||
int do_repaint;
|
||||
|
||||
squish_check();
|
||||
do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
|
||||
hit_eof = 0;
|
||||
while (--n >= 0)
|
||||
{
|
||||
/*
|
||||
* Get the previous line of input.
|
||||
*/
|
||||
pos = back_line(pos);
|
||||
if (pos == NULL_POSITION)
|
||||
break;
|
||||
/*
|
||||
* Add the position of the previous line to the position table.
|
||||
* Display the line on the screen.
|
||||
*/
|
||||
add_back_pos(pos);
|
||||
if (!do_repaint)
|
||||
{
|
||||
home();
|
||||
add_line();
|
||||
put_line();
|
||||
}
|
||||
}
|
||||
|
||||
eof_check();
|
||||
if (do_repaint)
|
||||
repaint();
|
||||
(void) currline(BOTTOM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display n more lines, forward.
|
||||
* Start just after the line currently displayed at the bottom of the screen.
|
||||
*/
|
||||
forward(n, only_last)
|
||||
int n;
|
||||
int only_last;
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
if (hit_eof) {
|
||||
/*
|
||||
* If we're trying to go forward from end-of-file,
|
||||
* go on to the next file.
|
||||
*/
|
||||
next_file(1);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = position(BOTTOM_PLUS_ONE);
|
||||
if (pos == NULL_POSITION)
|
||||
{
|
||||
hit_eof++;
|
||||
return;
|
||||
}
|
||||
forw(n, pos, only_last);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display n more lines, backward.
|
||||
* Start just before the line currently displayed at the top of the screen.
|
||||
*/
|
||||
backward(n, only_last)
|
||||
int n;
|
||||
int only_last;
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
pos = position(TOP);
|
||||
/*
|
||||
* This will almost never happen, because the top line is almost
|
||||
* never empty.
|
||||
*/
|
||||
if (pos == NULL_POSITION)
|
||||
return;
|
||||
back(n, pos, only_last);
|
||||
}
|
||||
|
||||
/*
|
||||
* Repaint the screen, starting from a specified position.
|
||||
*/
|
||||
prepaint(pos)
|
||||
off_t pos;
|
||||
{
|
||||
hit_eof = 0;
|
||||
forw(sc_height-1, pos, 0);
|
||||
screen_trashed = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Repaint the screen.
|
||||
*/
|
||||
repaint()
|
||||
{
|
||||
/*
|
||||
* Start at the line currently at the top of the screen
|
||||
* and redisplay the screen.
|
||||
*/
|
||||
prepaint(position(TOP));
|
||||
}
|
||||
|
||||
/*
|
||||
* Jump to the end of the file.
|
||||
* It is more convenient to paint the screen backward,
|
||||
* from the end of the file toward the beginning.
|
||||
*/
|
||||
jump_forw()
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
if (ch_end_seek())
|
||||
{
|
||||
error("Cannot seek to end of file");
|
||||
return;
|
||||
}
|
||||
lastmark();
|
||||
pos = ch_tell();
|
||||
clear();
|
||||
pos_clear();
|
||||
add_back_pos(pos);
|
||||
back(sc_height - 1, pos, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Jump to line n in the file.
|
||||
*/
|
||||
jump_back(n)
|
||||
register int n;
|
||||
{
|
||||
register int c, nlines;
|
||||
|
||||
/*
|
||||
* This is done the slow way, by starting at the beginning
|
||||
* of the file and counting newlines.
|
||||
*
|
||||
* {{ Now that we have line numbering (in linenum.c),
|
||||
* we could improve on this by starting at the
|
||||
* nearest known line rather than at the beginning. }}
|
||||
*/
|
||||
if (ch_seek((off_t)0)) {
|
||||
/*
|
||||
* Probably a pipe with beginning of file no longer buffered.
|
||||
* If he wants to go to line 1, we do the best we can,
|
||||
* by going to the first line which is still buffered.
|
||||
*/
|
||||
if (n <= 1 && ch_beg_seek() == 0)
|
||||
jump_loc(ch_tell());
|
||||
error("Cannot get to beginning of file");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start counting lines.
|
||||
*/
|
||||
for (nlines = 1; nlines < n; nlines++)
|
||||
while ((c = ch_forw_get()) != '\n')
|
||||
if (c == EOI) {
|
||||
char message[40];
|
||||
(void)sprintf(message, "File has only %d lines",
|
||||
nlines - 1);
|
||||
error(message);
|
||||
return;
|
||||
}
|
||||
jump_loc(ch_tell());
|
||||
}
|
||||
|
||||
/*
|
||||
* Jump to a specified percentage into the file.
|
||||
* This is a poor compensation for not being able to
|
||||
* quickly jump to a specific line number.
|
||||
*/
|
||||
jump_percent(percent)
|
||||
int percent;
|
||||
{
|
||||
off_t pos, len, ch_length();
|
||||
register int c;
|
||||
|
||||
/*
|
||||
* Determine the position in the file
|
||||
* (the specified percentage of the file's length).
|
||||
*/
|
||||
if ((len = ch_length()) == NULL_POSITION)
|
||||
{
|
||||
error("Don't know length of file");
|
||||
return;
|
||||
}
|
||||
pos = (percent * len) / 100;
|
||||
|
||||
/*
|
||||
* Back up to the beginning of the line.
|
||||
*/
|
||||
if (ch_seek(pos) == 0)
|
||||
{
|
||||
while ((c = ch_back_get()) != '\n' && c != EOI)
|
||||
;
|
||||
if (c == '\n')
|
||||
(void) ch_forw_get();
|
||||
pos = ch_tell();
|
||||
}
|
||||
jump_loc(pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Jump to a specified position in the file.
|
||||
*/
|
||||
jump_loc(pos)
|
||||
off_t pos;
|
||||
{
|
||||
register int nline;
|
||||
off_t tpos;
|
||||
|
||||
if ((nline = onscreen(pos)) >= 0) {
|
||||
/*
|
||||
* The line is currently displayed.
|
||||
* Just scroll there.
|
||||
*/
|
||||
forw(nline, position(BOTTOM_PLUS_ONE), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Line is not on screen.
|
||||
* Seek to the desired location.
|
||||
*/
|
||||
if (ch_seek(pos)) {
|
||||
error("Cannot seek to that position");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the desired line is BEFORE the currently displayed screen.
|
||||
* If so, then move forward far enough so the line we're on will be
|
||||
* at the bottom of the screen, in order to be able to call back()
|
||||
* to make the screen scroll backwards & put the line at the top of
|
||||
* the screen.
|
||||
* {{ This seems inefficient, but it's not so bad,
|
||||
* since we can never move forward more than a
|
||||
* screenful before we stop to redraw the screen. }}
|
||||
*/
|
||||
tpos = position(TOP);
|
||||
if (tpos != NULL_POSITION && pos < tpos) {
|
||||
off_t npos = pos;
|
||||
/*
|
||||
* Note that we can't forw_line() past tpos here,
|
||||
* so there should be no EOI at this stage.
|
||||
*/
|
||||
for (nline = 0; npos < tpos && nline < sc_height - 1; nline++)
|
||||
npos = forw_line(npos);
|
||||
|
||||
if (npos < tpos) {
|
||||
/*
|
||||
* More than a screenful back.
|
||||
*/
|
||||
lastmark();
|
||||
clear();
|
||||
pos_clear();
|
||||
add_back_pos(npos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that back() will repaint() if nline > back_scroll.
|
||||
*/
|
||||
back(nline, npos, 0);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Remember where we were; clear and paint the screen.
|
||||
*/
|
||||
lastmark();
|
||||
prepaint(pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* The table of marks.
|
||||
* A mark is simply a position in the file.
|
||||
*/
|
||||
#define NMARKS (27) /* 26 for a-z plus one for quote */
|
||||
#define LASTMARK (NMARKS-1) /* For quote */
|
||||
static off_t marks[NMARKS];
|
||||
|
||||
/*
|
||||
* Initialize the mark table to show no marks are set.
|
||||
*/
|
||||
init_mark()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NMARKS; i++)
|
||||
marks[i] = NULL_POSITION;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if a mark letter is valid (between a and z).
|
||||
*/
|
||||
static int
|
||||
badmark(c)
|
||||
int c;
|
||||
{
|
||||
if (c < 'a' || c > 'z')
|
||||
{
|
||||
error("Choose a letter between 'a' and 'z'");
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a mark.
|
||||
*/
|
||||
setmark(c)
|
||||
int c;
|
||||
{
|
||||
if (badmark(c))
|
||||
return;
|
||||
marks[c-'a'] = position(TOP);
|
||||
}
|
||||
|
||||
lastmark()
|
||||
{
|
||||
marks[LASTMARK] = position(TOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go to a previously set mark.
|
||||
*/
|
||||
gomark(c)
|
||||
int c;
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
if (c == '\'') {
|
||||
pos = marks[LASTMARK];
|
||||
if (pos == NULL_POSITION)
|
||||
pos = 0;
|
||||
}
|
||||
else {
|
||||
if (badmark(c))
|
||||
return;
|
||||
pos = marks[c-'a'];
|
||||
if (pos == NULL_POSITION) {
|
||||
error("mark not set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
jump_loc(pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the backwards scroll limit.
|
||||
* Must call this function instead of just using the value of
|
||||
* back_scroll, because the default case depends on sc_height and
|
||||
* top_scroll, as well as back_scroll.
|
||||
*/
|
||||
get_back_scroll()
|
||||
{
|
||||
if (back_scroll >= 0)
|
||||
return (back_scroll);
|
||||
if (top_scroll)
|
||||
return (sc_height - 2);
|
||||
return (sc_height - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for the n-th occurence of a specified pattern,
|
||||
* either forward or backward.
|
||||
*/
|
||||
search(search_forward, pattern, n, wantmatch)
|
||||
register int search_forward;
|
||||
register char *pattern;
|
||||
register int n;
|
||||
int wantmatch;
|
||||
{
|
||||
off_t pos, linepos;
|
||||
register char *p;
|
||||
register char *q;
|
||||
int linenum;
|
||||
int linematch;
|
||||
#ifdef REGEX
|
||||
static regex_t *cpattern = NULL;
|
||||
#else
|
||||
#ifdef RECOMP
|
||||
char *re_comp();
|
||||
char *errmsg;
|
||||
#else
|
||||
#ifdef REGCMP
|
||||
char *regcmp();
|
||||
static char *cpattern = NULL;
|
||||
#else
|
||||
static char lpbuf[100];
|
||||
static char *last_pattern = NULL;
|
||||
char *strcpy();
|
||||
#endif
|
||||
#endif
|
||||
#endif /*REGEX */
|
||||
/*
|
||||
* For a caseless search, convert any uppercase in the pattern to
|
||||
* lowercase.
|
||||
*/
|
||||
if (caseless && pattern != NULL)
|
||||
for (p = pattern; *p; p++)
|
||||
if (isupper(*p))
|
||||
*p = tolower(*p);
|
||||
#ifdef REGEX
|
||||
if (pattern == NULL || *pattern == '\0')
|
||||
{
|
||||
/*
|
||||
* A null pattern means use the previous pattern.
|
||||
* The compiled previous pattern is in cpattern, so just use it.
|
||||
*/
|
||||
if (cpattern == NULL)
|
||||
{
|
||||
error("No previous regular expression");
|
||||
return(0);
|
||||
}
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Otherwise compile the given pattern.
|
||||
*/
|
||||
if (cpattern == NULL
|
||||
&& (cpattern = (regex_t *) malloc(sizeof(regex_t))) == NULL) {
|
||||
error("cannot allocate memory");
|
||||
quit();
|
||||
}
|
||||
else
|
||||
regfree(cpattern);
|
||||
if (regcomp(cpattern, pattern, 0))
|
||||
{
|
||||
error("Invalid pattern");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef RECOMP
|
||||
|
||||
/*
|
||||
* (re_comp handles a null pattern internally,
|
||||
* so there is no need to check for a null pattern here.)
|
||||
*/
|
||||
if ((errmsg = re_comp(pattern)) != NULL)
|
||||
{
|
||||
error(errmsg);
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
#ifdef REGCMP
|
||||
if (pattern == NULL || *pattern == '\0')
|
||||
{
|
||||
/*
|
||||
* A null pattern means use the previous pattern.
|
||||
* The compiled previous pattern is in cpattern, so just use it.
|
||||
*/
|
||||
if (cpattern == NULL)
|
||||
{
|
||||
error("No previous regular expression");
|
||||
return(0);
|
||||
}
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Otherwise compile the given pattern.
|
||||
*/
|
||||
char *s;
|
||||
if ((s = regcmp(pattern, 0)) == NULL)
|
||||
{
|
||||
error("Invalid pattern");
|
||||
return(0);
|
||||
}
|
||||
if (cpattern != NULL)
|
||||
free(cpattern);
|
||||
cpattern = s;
|
||||
}
|
||||
#else
|
||||
if (pattern == NULL || *pattern == '\0')
|
||||
{
|
||||
/*
|
||||
* Null pattern means use the previous pattern.
|
||||
*/
|
||||
if (last_pattern == NULL)
|
||||
{
|
||||
error("No previous regular expression");
|
||||
return(0);
|
||||
}
|
||||
pattern = last_pattern;
|
||||
} else
|
||||
{
|
||||
(void)strcpy(lpbuf, pattern);
|
||||
last_pattern = lpbuf;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif /* REGEX */
|
||||
|
||||
/*
|
||||
* Figure out where to start the search.
|
||||
*/
|
||||
|
||||
if (position(TOP) == NULL_POSITION) {
|
||||
/*
|
||||
* Nothing is currently displayed. Start at the beginning
|
||||
* of the file. (This case is mainly for searches from the
|
||||
* command line.
|
||||
*/
|
||||
pos = (off_t)0;
|
||||
} else if (!search_forward) {
|
||||
/*
|
||||
* Backward search: start just before the top line
|
||||
* displayed on the screen.
|
||||
*/
|
||||
pos = position(TOP);
|
||||
} else {
|
||||
/*
|
||||
* Start at the second screen line displayed on the screen.
|
||||
*/
|
||||
pos = position(TOP_PLUS_ONE);
|
||||
}
|
||||
|
||||
if (pos == NULL_POSITION)
|
||||
{
|
||||
/*
|
||||
* Can't find anyplace to start searching from.
|
||||
*/
|
||||
error("Nothing to search");
|
||||
return(0);
|
||||
}
|
||||
|
||||
linenum = find_linenum(pos);
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
* Get lines until we find a matching one or
|
||||
* until we hit end-of-file (or beginning-of-file
|
||||
* if we're going backwards).
|
||||
*/
|
||||
if (sigs)
|
||||
/*
|
||||
* A signal aborts the search.
|
||||
*/
|
||||
return(0);
|
||||
|
||||
if (search_forward)
|
||||
{
|
||||
/*
|
||||
* Read the next line, and save the
|
||||
* starting position of that line in linepos.
|
||||
*/
|
||||
linepos = pos;
|
||||
pos = forw_raw_line(pos);
|
||||
if (linenum != 0)
|
||||
linenum++;
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Read the previous line and save the
|
||||
* starting position of that line in linepos.
|
||||
*/
|
||||
pos = back_raw_line(pos);
|
||||
linepos = pos;
|
||||
if (linenum != 0)
|
||||
linenum--;
|
||||
}
|
||||
|
||||
if (pos == NULL_POSITION)
|
||||
{
|
||||
/*
|
||||
* We hit EOF/BOF without a match.
|
||||
*/
|
||||
error("Pattern not found");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're using line numbers, we might as well
|
||||
* remember the information we have now (the position
|
||||
* and line number of the current line).
|
||||
*/
|
||||
if (linenums)
|
||||
add_lnum(linenum, pos);
|
||||
|
||||
/*
|
||||
* If this is a caseless search, convert uppercase in the
|
||||
* input line to lowercase.
|
||||
*/
|
||||
if (caseless)
|
||||
for (p = q = line; *p; p++, q++)
|
||||
*q = isupper(*p) ? tolower(*p) : *p;
|
||||
|
||||
/*
|
||||
* Remove any backspaces along with the preceeding char.
|
||||
* This allows us to match text which is underlined or
|
||||
* overstruck.
|
||||
*/
|
||||
for (p = q = line; *p; p++, q++)
|
||||
if (q > line && *p == '\b')
|
||||
/* Delete BS and preceeding char. */
|
||||
q -= 2;
|
||||
else
|
||||
/* Otherwise, just copy. */
|
||||
*q = *p;
|
||||
|
||||
/*
|
||||
* Test the next line to see if we have a match.
|
||||
* This is done in a variety of ways, depending
|
||||
* on what pattern matching functions are available.
|
||||
*/
|
||||
#ifdef REGEX
|
||||
linematch = !regexec(cpattern, line, 0, NULL, 0);
|
||||
#else
|
||||
#ifdef REGCMP
|
||||
linematch = (regex(cpattern, line) != NULL);
|
||||
#else
|
||||
#ifdef RECOMP
|
||||
linematch = (re_exec(line) == 1);
|
||||
#else
|
||||
linematch = match(pattern, line);
|
||||
#endif
|
||||
#endif
|
||||
#endif /* REGEX */
|
||||
/*
|
||||
* We are successful if wantmatch and linematch are
|
||||
* both true (want a match and got it),
|
||||
* or both false (want a non-match and got it).
|
||||
*/
|
||||
if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
|
||||
--n <= 0)
|
||||
/*
|
||||
* Found the line.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
jump_loc(linepos);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#if !defined(REGCMP) && !defined(RECOMP) && !defined(REGEX)
|
||||
/*
|
||||
* We have neither regcmp() nor re_comp().
|
||||
* We use this function to do simple pattern matching.
|
||||
* It supports no metacharacters like *, etc.
|
||||
*/
|
||||
static
|
||||
match(pattern, buf)
|
||||
char *pattern, *buf;
|
||||
{
|
||||
register char *pp, *lp;
|
||||
|
||||
for ( ; *buf != '\0'; buf++)
|
||||
{
|
||||
for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
|
||||
if (*pp == '\0' || *lp == '\0')
|
||||
break;
|
||||
if (*pp == '\0')
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif
|
@ -1,620 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)screen.c 5.8 (Berkeley) 6/28/92"; */
|
||||
static char *rcsid = "$Id: screen.c,v 1.6 1995/05/16 22:18:33 jtc Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines which deal with the characteristics of the terminal.
|
||||
* Uses termcap to be as terminal-independent as possible.
|
||||
*
|
||||
* {{ Someday this should be rewritten to use curses. }}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <less.h>
|
||||
|
||||
#ifdef TERMIOS
|
||||
#include <termios.h>
|
||||
#else
|
||||
#ifdef TERMIO
|
||||
#include <termio.h>
|
||||
#else
|
||||
#include <sgtty.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* pull in TIOCGWINSZ on BSD systems */
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifndef TIOCGWINSZ
|
||||
/*
|
||||
* For the Unix PC (ATT 7300 & 3B1):
|
||||
* Since WIOCGETD is defined in sys/window.h, we can't use that to decide
|
||||
* whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead.
|
||||
*/
|
||||
#include <sys/signal.h>
|
||||
#ifdef SIGPHONE
|
||||
#include <sys/window.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Strings passed to tputs() to do various terminal functions.
|
||||
*/
|
||||
static char
|
||||
*sc_pad, /* Pad string */
|
||||
*sc_home, /* Cursor home */
|
||||
*sc_addline, /* Add line, scroll down following lines */
|
||||
*sc_lower_left, /* Cursor to last line, first column */
|
||||
*sc_move, /* General cursor positioning */
|
||||
*sc_clear, /* Clear screen */
|
||||
*sc_eol_clear, /* Clear to end of line */
|
||||
*sc_s_in, /* Enter standout (highlighted) mode */
|
||||
*sc_s_out, /* Exit standout mode */
|
||||
*sc_u_in, /* Enter underline mode */
|
||||
*sc_u_out, /* Exit underline mode */
|
||||
*sc_b_in, /* Enter bold mode */
|
||||
*sc_b_out, /* Exit bold mode */
|
||||
*sc_backspace, /* Backspace cursor */
|
||||
*sc_init, /* Startup terminal initialization */
|
||||
*sc_deinit; /* Exit terminal de-intialization */
|
||||
|
||||
int auto_wrap; /* Terminal does \r\n when write past margin */
|
||||
int ignaw; /* Terminal ignores \n immediately after wrap */
|
||||
/* The user's erase and line-kill chars */
|
||||
int erase_char, kill_char, werase_char;
|
||||
int sc_width, sc_height = -1; /* Height & width of screen */
|
||||
int sc_window = -1; /* window size for forward and backward */
|
||||
int bo_width, be_width; /* Printing width of boldface sequences */
|
||||
int ul_width, ue_width; /* Printing width of underline sequences */
|
||||
int so_width, se_width; /* Printing width of standout sequences */
|
||||
|
||||
/*
|
||||
* These two variables are sometimes defined in,
|
||||
* and needed by, the termcap library.
|
||||
* It may be necessary on some systems to declare them extern here.
|
||||
*/
|
||||
#ifdef TERMIOS
|
||||
/*extern*/ speed_t ospeed; /* Terminal output baud rate */
|
||||
#else
|
||||
/*extern*/ short ospeed; /* Terminal output baud rate */
|
||||
#endif
|
||||
/*extern*/ char PC; /* Pad character */
|
||||
|
||||
extern int back_scroll;
|
||||
char *tgetstr();
|
||||
char *tgoto();
|
||||
|
||||
/*
|
||||
* Change terminal to "raw mode", or restore to "normal" mode.
|
||||
* "Raw mode" means
|
||||
* 1. An outstanding read will complete on receipt of a single keystroke.
|
||||
* 2. Input is not echoed.
|
||||
* 3. On output, \n is mapped to \r\n.
|
||||
* 4. \t is NOT expanded into spaces.
|
||||
* 5. Signal-causing characters such as ctrl-C (interrupt),
|
||||
* etc. are NOT disabled.
|
||||
* It doesn't matter whether an input \n is mapped to \r, or vice versa.
|
||||
*/
|
||||
raw_mode(on)
|
||||
int on;
|
||||
{
|
||||
#ifdef TERMIOS
|
||||
struct termios s;
|
||||
static struct termios save_term;
|
||||
|
||||
if (on)
|
||||
{
|
||||
/*
|
||||
* Get terminal modes.
|
||||
*/
|
||||
(void)tcgetattr(2, &s);
|
||||
|
||||
/*
|
||||
* Save modes and set certain variables dependent on modes.
|
||||
*/
|
||||
save_term = s;
|
||||
ospeed = cfgetospeed(&s);
|
||||
erase_char = s.c_cc[VERASE];
|
||||
kill_char = s.c_cc[VKILL];
|
||||
werase_char = s.c_cc[VWERASE];
|
||||
|
||||
/*
|
||||
* Set the modes to the way we want them.
|
||||
*/
|
||||
s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
|
||||
s.c_oflag |= (OPOST|ONLCR
|
||||
#ifdef TAB3
|
||||
|TAB3
|
||||
#endif
|
||||
);
|
||||
#ifdef OCRNL
|
||||
s.c_oflag &= ~(OCRNL|ONLRET|ONOCR);
|
||||
#endif
|
||||
s.c_cc[VMIN] = 1;
|
||||
s.c_cc[VTIME] = 0;
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Restore saved modes.
|
||||
*/
|
||||
s = save_term;
|
||||
}
|
||||
(void)tcsetattr(2, TCSADRAIN, &s);
|
||||
#else
|
||||
#ifdef TERMIO
|
||||
struct termio s;
|
||||
static struct termio save_term;
|
||||
|
||||
if (on)
|
||||
{
|
||||
/*
|
||||
* Get terminal modes.
|
||||
*/
|
||||
(void)ioctl(2, TCGETA, &s);
|
||||
|
||||
/*
|
||||
* Save modes and set certain variables dependent on modes.
|
||||
*/
|
||||
save_term = s;
|
||||
ospeed = s.c_cflag & CBAUD;
|
||||
erase_char = s.c_cc[VERASE];
|
||||
kill_char = s.c_cc[VKILL];
|
||||
werase_char = s.c_cc[VWERASE];
|
||||
|
||||
/*
|
||||
* Set the modes to the way we want them.
|
||||
*/
|
||||
s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
|
||||
s.c_oflag |= (OPOST|ONLCR|TAB3);
|
||||
s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
|
||||
s.c_cc[VMIN] = 1;
|
||||
s.c_cc[VTIME] = 0;
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Restore saved modes.
|
||||
*/
|
||||
s = save_term;
|
||||
}
|
||||
(void)ioctl(2, TCSETAW, &s);
|
||||
#else
|
||||
struct sgttyb s;
|
||||
struct ltchars l;
|
||||
static struct sgttyb save_term;
|
||||
|
||||
if (on)
|
||||
{
|
||||
/*
|
||||
* Get terminal modes.
|
||||
*/
|
||||
(void)ioctl(2, TIOCGETP, &s);
|
||||
(void)ioctl(2, TIOCGLTC, &l);
|
||||
|
||||
/*
|
||||
* Save modes and set certain variables dependent on modes.
|
||||
*/
|
||||
save_term = s;
|
||||
ospeed = s.sg_ospeed;
|
||||
erase_char = s.sg_erase;
|
||||
kill_char = s.sg_kill;
|
||||
werase_char = l.t_werasc;
|
||||
|
||||
/*
|
||||
* Set the modes to the way we want them.
|
||||
*/
|
||||
s.sg_flags |= CBREAK;
|
||||
s.sg_flags &= ~(ECHO|XTABS);
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Restore saved modes.
|
||||
*/
|
||||
s = save_term;
|
||||
}
|
||||
(void)ioctl(2, TIOCSETN, &s);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Get terminal capabilities via termcap.
|
||||
*/
|
||||
get_term()
|
||||
{
|
||||
char termbuf[2048];
|
||||
char *sp;
|
||||
char *term;
|
||||
int hard;
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize w;
|
||||
#else
|
||||
#ifdef WIOCGETD
|
||||
struct uwdata w;
|
||||
#endif
|
||||
#endif
|
||||
static char sbuf[1024];
|
||||
|
||||
char *getenv(), *strcpy();
|
||||
|
||||
/*
|
||||
* Find out what kind of terminal this is.
|
||||
*/
|
||||
if ((term = getenv("TERM")) == NULL)
|
||||
term = "unknown";
|
||||
if (tgetent(termbuf, term) <= 0)
|
||||
(void)strcpy(termbuf, "dumb:co#80:hc:");
|
||||
|
||||
/*
|
||||
* Get size of the screen.
|
||||
*/
|
||||
#ifdef TIOCGWINSZ
|
||||
if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
|
||||
sc_height = w.ws_row;
|
||||
#else
|
||||
#ifdef WIOCGETD
|
||||
if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0)
|
||||
sc_height = w.uw_height/w.uw_vs;
|
||||
#endif
|
||||
#endif
|
||||
else
|
||||
sc_height = tgetnum("li");
|
||||
hard = (sc_height < 0 || tgetflag("hc"));
|
||||
if (hard) {
|
||||
/* Oh no, this is a hardcopy terminal. */
|
||||
sc_height = 24;
|
||||
}
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
|
||||
sc_width = w.ws_col;
|
||||
else
|
||||
#ifdef WIOCGETD
|
||||
if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0)
|
||||
sc_width = w.uw_width/w.uw_hs;
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
sc_width = tgetnum("co");
|
||||
if (sc_width < 0)
|
||||
sc_width = 80;
|
||||
|
||||
auto_wrap = tgetflag("am");
|
||||
ignaw = tgetflag("xn");
|
||||
|
||||
/*
|
||||
* Assumes termcap variable "sg" is the printing width of
|
||||
* the standout sequence, the end standout sequence,
|
||||
* the underline sequence, the end underline sequence,
|
||||
* the boldface sequence, and the end boldface sequence.
|
||||
*/
|
||||
if ((so_width = tgetnum("sg")) < 0)
|
||||
so_width = 0;
|
||||
be_width = bo_width = ue_width = ul_width = se_width = so_width;
|
||||
|
||||
/*
|
||||
* Get various string-valued capabilities.
|
||||
*/
|
||||
sp = sbuf;
|
||||
|
||||
sc_pad = tgetstr("pc", &sp);
|
||||
if (sc_pad != NULL)
|
||||
PC = *sc_pad;
|
||||
|
||||
sc_init = tgetstr("ti", &sp);
|
||||
if (sc_init == NULL)
|
||||
sc_init = "";
|
||||
|
||||
sc_deinit= tgetstr("te", &sp);
|
||||
if (sc_deinit == NULL)
|
||||
sc_deinit = "";
|
||||
|
||||
sc_eol_clear = tgetstr("ce", &sp);
|
||||
if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
|
||||
{
|
||||
sc_eol_clear = "";
|
||||
}
|
||||
|
||||
sc_clear = tgetstr("cl", &sp);
|
||||
if (hard || sc_clear == NULL || *sc_clear == '\0')
|
||||
{
|
||||
sc_clear = "\n\n";
|
||||
}
|
||||
|
||||
sc_move = tgetstr("cm", &sp);
|
||||
if (hard || sc_move == NULL || *sc_move == '\0')
|
||||
{
|
||||
/*
|
||||
* This is not an error here, because we don't
|
||||
* always need sc_move.
|
||||
* We need it only if we don't have home or lower-left.
|
||||
*/
|
||||
sc_move = "";
|
||||
}
|
||||
|
||||
sc_s_in = tgetstr("so", &sp);
|
||||
if (hard || sc_s_in == NULL)
|
||||
sc_s_in = "";
|
||||
|
||||
sc_s_out = tgetstr("se", &sp);
|
||||
if (hard || sc_s_out == NULL)
|
||||
sc_s_out = "";
|
||||
|
||||
sc_u_in = tgetstr("us", &sp);
|
||||
if (hard || sc_u_in == NULL)
|
||||
sc_u_in = sc_s_in;
|
||||
|
||||
sc_u_out = tgetstr("ue", &sp);
|
||||
if (hard || sc_u_out == NULL)
|
||||
sc_u_out = sc_s_out;
|
||||
|
||||
sc_b_in = tgetstr("md", &sp);
|
||||
if (hard || sc_b_in == NULL)
|
||||
{
|
||||
sc_b_in = sc_s_in;
|
||||
sc_b_out = sc_s_out;
|
||||
} else
|
||||
{
|
||||
sc_b_out = tgetstr("me", &sp);
|
||||
if (hard || sc_b_out == NULL)
|
||||
sc_b_out = "";
|
||||
}
|
||||
|
||||
sc_home = tgetstr("ho", &sp);
|
||||
if (hard || sc_home == NULL || *sc_home == '\0')
|
||||
{
|
||||
if (*sc_move == '\0')
|
||||
{
|
||||
/*
|
||||
* This last resort for sc_home is supposed to
|
||||
* be an up-arrow suggesting moving to the
|
||||
* top of the "virtual screen". (The one in
|
||||
* your imagination as you try to use this on
|
||||
* a hard copy terminal.)
|
||||
*/
|
||||
sc_home = "|\b^";
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* No "home" string,
|
||||
* but we can use "move(0,0)".
|
||||
*/
|
||||
(void)strcpy(sp, tgoto(sc_move, 0, 0));
|
||||
sc_home = sp;
|
||||
sp += strlen(sp) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
sc_lower_left = tgetstr("ll", &sp);
|
||||
if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
|
||||
{
|
||||
if (*sc_move == '\0')
|
||||
{
|
||||
sc_lower_left = "\r";
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* No "lower-left" string,
|
||||
* but we can use "move(0,last-line)".
|
||||
*/
|
||||
(void)strcpy(sp, tgoto(sc_move, 0, sc_height-1));
|
||||
sc_lower_left = sp;
|
||||
sp += strlen(sp) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To add a line at top of screen and scroll the display down,
|
||||
* we use "al" (add line) or "sr" (scroll reverse).
|
||||
*/
|
||||
if ((sc_addline = tgetstr("al", &sp)) == NULL ||
|
||||
*sc_addline == '\0')
|
||||
sc_addline = tgetstr("sr", &sp);
|
||||
|
||||
if (hard || sc_addline == NULL || *sc_addline == '\0')
|
||||
{
|
||||
sc_addline = "";
|
||||
/* Force repaint on any backward movement */
|
||||
back_scroll = 0;
|
||||
}
|
||||
|
||||
if (tgetflag("bs"))
|
||||
sc_backspace = "\b";
|
||||
else
|
||||
{
|
||||
sc_backspace = tgetstr("bc", &sp);
|
||||
if (sc_backspace == NULL || *sc_backspace == '\0')
|
||||
sc_backspace = "\b";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Below are the functions which perform all the
|
||||
* terminal-specific screen manipulation.
|
||||
*/
|
||||
|
||||
int putchr();
|
||||
|
||||
/*
|
||||
* Initialize terminal
|
||||
*/
|
||||
init()
|
||||
{
|
||||
/*
|
||||
* This loses for terminals with termcap entries with ti/te strings
|
||||
* that switch to/from an alternate screen.
|
||||
*/
|
||||
#if 0
|
||||
tputs(sc_init, sc_height, putchr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Deinitialize terminal
|
||||
*/
|
||||
deinit()
|
||||
{
|
||||
#if 0
|
||||
tputs(sc_deinit, sc_height, putchr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Home cursor (move to upper left corner of screen).
|
||||
*/
|
||||
home()
|
||||
{
|
||||
tputs(sc_home, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a blank line (called with cursor at home).
|
||||
* Should scroll the display down.
|
||||
*/
|
||||
add_line()
|
||||
{
|
||||
tputs(sc_addline, sc_height, putchr);
|
||||
}
|
||||
|
||||
int short_file; /* if file less than a screen */
|
||||
lower_left()
|
||||
{
|
||||
if (short_file) {
|
||||
putchr('\r');
|
||||
flush();
|
||||
}
|
||||
else
|
||||
tputs(sc_lower_left, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ring the terminal bell.
|
||||
*/
|
||||
bell()
|
||||
{
|
||||
putchr('\7');
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the screen.
|
||||
*/
|
||||
clear()
|
||||
{
|
||||
tputs(sc_clear, sc_height, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear from the cursor to the end of the cursor's line.
|
||||
* {{ This must not move the cursor. }}
|
||||
*/
|
||||
clear_eol()
|
||||
{
|
||||
tputs(sc_eol_clear, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin "standout" (bold, underline, or whatever).
|
||||
*/
|
||||
so_enter()
|
||||
{
|
||||
tputs(sc_s_in, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* End "standout".
|
||||
*/
|
||||
so_exit()
|
||||
{
|
||||
tputs(sc_s_out, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin "underline" (hopefully real underlining,
|
||||
* otherwise whatever the terminal provides).
|
||||
*/
|
||||
ul_enter()
|
||||
{
|
||||
tputs(sc_u_in, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* End "underline".
|
||||
*/
|
||||
ul_exit()
|
||||
{
|
||||
tputs(sc_u_out, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin "bold"
|
||||
*/
|
||||
bo_enter()
|
||||
{
|
||||
tputs(sc_b_in, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* End "bold".
|
||||
*/
|
||||
bo_exit()
|
||||
{
|
||||
tputs(sc_b_out, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase the character to the left of the cursor
|
||||
* and move the cursor left.
|
||||
*/
|
||||
backspace()
|
||||
{
|
||||
/*
|
||||
* Try to erase the previous character by overstriking with a space.
|
||||
*/
|
||||
tputs(sc_backspace, 1, putchr);
|
||||
putchr(' ');
|
||||
tputs(sc_backspace, 1, putchr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a plain backspace, without erasing the previous char.
|
||||
*/
|
||||
putbs()
|
||||
{
|
||||
tputs(sc_backspace, 1, putchr);
|
||||
}
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)signal.c 5.8 (Berkeley) 3/1/91"; */
|
||||
static char *rcsid = "$Id: signal.c,v 1.2 1993/11/09 05:13:25 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines dealing with signals.
|
||||
*
|
||||
* A signal usually merely causes a bit to be set in the "signals" word.
|
||||
* At some convenient time, the mainline code checks to see if any
|
||||
* signals need processing by calling psignal().
|
||||
* If we happen to be reading from a file [in iread()] at the time
|
||||
* the signal is received, we call intread to interrupt the iread.
|
||||
*/
|
||||
|
||||
#include <less.h>
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* "sigs" contains bits indicating signals which need to be processed.
|
||||
*/
|
||||
int sigs;
|
||||
|
||||
#ifdef SIGTSTP
|
||||
#define S_STOP 02
|
||||
#endif
|
||||
#if defined(SIGWINCH) || defined(SIGWIND)
|
||||
#define S_WINCH 04
|
||||
#endif
|
||||
|
||||
extern int sc_width, sc_height;
|
||||
extern int screen_trashed;
|
||||
extern int lnloop;
|
||||
extern int linenums;
|
||||
extern int scroll;
|
||||
extern int reading;
|
||||
|
||||
#ifdef SIGTSTP
|
||||
/*
|
||||
* "Stop" (^Z) signal handler.
|
||||
*/
|
||||
static void
|
||||
stop()
|
||||
{
|
||||
(void)signal(SIGTSTP, stop);
|
||||
sigs |= S_STOP;
|
||||
if (reading)
|
||||
intread();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SIGWINCH
|
||||
/*
|
||||
* "Window" change handler
|
||||
*/
|
||||
void
|
||||
winch()
|
||||
{
|
||||
(void)signal(SIGWINCH, winch);
|
||||
sigs |= S_WINCH;
|
||||
if (reading)
|
||||
intread();
|
||||
}
|
||||
#else
|
||||
#ifdef SIGWIND
|
||||
/*
|
||||
* "Window" change handler
|
||||
*/
|
||||
winch()
|
||||
{
|
||||
(void)signal(SIGWIND, winch);
|
||||
sigs |= S_WINCH;
|
||||
if (reading)
|
||||
intread();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void
|
||||
purgeandquit()
|
||||
{
|
||||
|
||||
purge(); /* purge buffered output */
|
||||
quit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the signal handlers.
|
||||
*/
|
||||
init_signals(on)
|
||||
int on;
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
/*
|
||||
* Set signal handlers.
|
||||
*/
|
||||
(void)signal(SIGINT, purgeandquit);
|
||||
#ifdef SIGTSTP
|
||||
(void)signal(SIGTSTP, stop);
|
||||
#endif
|
||||
#ifdef SIGWINCH
|
||||
(void)signal(SIGWINCH, winch);
|
||||
#else
|
||||
#ifdef SIGWIND
|
||||
(void)signal(SIGWIND, winch);
|
||||
#endif
|
||||
#endif
|
||||
} else
|
||||
{
|
||||
/*
|
||||
* Restore signals to defaults.
|
||||
*/
|
||||
(void)signal(SIGINT, SIG_DFL);
|
||||
#ifdef SIGTSTP
|
||||
(void)signal(SIGTSTP, SIG_DFL);
|
||||
#endif
|
||||
#ifdef SIGWINCH
|
||||
(void)signal(SIGWINCH, SIG_IGN);
|
||||
#endif
|
||||
#ifdef SIGWIND
|
||||
(void)signal(SIGWIND, SIG_IGN);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process any signals we have received.
|
||||
* A received signal cause a bit to be set in "sigs".
|
||||
*/
|
||||
psignals()
|
||||
{
|
||||
register int tsignals;
|
||||
|
||||
if ((tsignals = sigs) == 0)
|
||||
return;
|
||||
sigs = 0;
|
||||
|
||||
#ifdef S_WINCH
|
||||
if (tsignals & S_WINCH)
|
||||
{
|
||||
int old_width, old_height;
|
||||
/*
|
||||
* Re-execute get_term() to read the new window size.
|
||||
*/
|
||||
old_width = sc_width;
|
||||
old_height = sc_height;
|
||||
get_term();
|
||||
if (sc_width != old_width || sc_height != old_height)
|
||||
{
|
||||
scroll = (sc_height + 1) / 2;
|
||||
screen_trashed = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef SIGTSTP
|
||||
if (tsignals & S_STOP)
|
||||
{
|
||||
/*
|
||||
* Clean up the terminal.
|
||||
*/
|
||||
#ifdef SIGTTOU
|
||||
(void)signal(SIGTTOU, SIG_IGN);
|
||||
#endif
|
||||
lower_left();
|
||||
clear_eol();
|
||||
deinit();
|
||||
(void)flush();
|
||||
raw_mode(0);
|
||||
#ifdef SIGTTOU
|
||||
(void)signal(SIGTTOU, SIG_DFL);
|
||||
#endif
|
||||
(void)signal(SIGTSTP, SIG_DFL);
|
||||
(void)kill(getpid(), SIGTSTP);
|
||||
/*
|
||||
* ... Bye bye. ...
|
||||
* Hopefully we'll be back later and resume here...
|
||||
* Reset the terminal and arrange to repaint the
|
||||
* screen when we get back to the main command loop.
|
||||
*/
|
||||
(void)signal(SIGTSTP, stop);
|
||||
raw_mode(1);
|
||||
init();
|
||||
screen_trashed = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)tags.c 5.5 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: tags.c,v 1.3 1994/12/24 17:17:14 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <less.h>
|
||||
|
||||
#define WHITESP(c) ((c)==' ' || (c)=='\t')
|
||||
|
||||
char *tagfile;
|
||||
char *tagpattern;
|
||||
|
||||
static char *tags = "tags";
|
||||
|
||||
extern int linenums;
|
||||
extern int sigs;
|
||||
extern char *line;
|
||||
|
||||
/*
|
||||
* Find a tag in the "tags" file.
|
||||
* Sets "tagfile" to the name of the file containing the tag,
|
||||
* and "tagpattern" to the search pattern which should be used
|
||||
* to find the tag.
|
||||
*/
|
||||
findtag(tag)
|
||||
register char *tag;
|
||||
{
|
||||
register char *p;
|
||||
register FILE *f;
|
||||
register int taglen;
|
||||
int search_char;
|
||||
static char tline[200];
|
||||
|
||||
if ((f = fopen(tags, "r")) == NULL)
|
||||
{
|
||||
error("No tags file");
|
||||
tagfile = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
taglen = strlen(tag);
|
||||
|
||||
/*
|
||||
* Search the tags file for the desired tag.
|
||||
*/
|
||||
while (fgets(tline, sizeof(tline), f) != NULL)
|
||||
{
|
||||
if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen]))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Found it.
|
||||
* The line contains the tag, the filename and the
|
||||
* pattern, separated by white space.
|
||||
* The pattern is surrounded by a pair of identical
|
||||
* search characters.
|
||||
* Parse the line and extract these parts.
|
||||
*/
|
||||
tagfile = tagpattern = NULL;
|
||||
|
||||
/*
|
||||
* Skip over the whitespace after the tag name.
|
||||
*/
|
||||
for (p = tline; !WHITESP(*p) && *p != '\0'; p++)
|
||||
continue;
|
||||
while (WHITESP(*p))
|
||||
p++;
|
||||
if (*p == '\0')
|
||||
/* File name is missing! */
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Save the file name.
|
||||
* Skip over the whitespace after the file name.
|
||||
*/
|
||||
tagfile = p;
|
||||
while (!WHITESP(*p) && *p != '\0')
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
while (WHITESP(*p))
|
||||
p++;
|
||||
if (*p == '\0')
|
||||
/* Pattern is missing! */
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Save the pattern.
|
||||
* Skip to the end of the pattern.
|
||||
* Delete the initial "^" and the final "$" from the pattern.
|
||||
*/
|
||||
search_char = *p++;
|
||||
if (*p == '^')
|
||||
p++;
|
||||
tagpattern = p;
|
||||
while (*p != search_char && *p != '\0')
|
||||
p++;
|
||||
if (p[-1] == '$')
|
||||
p--;
|
||||
*p = '\0';
|
||||
|
||||
(void)fclose(f);
|
||||
return;
|
||||
}
|
||||
(void)fclose(f);
|
||||
error("No such tag in tags file");
|
||||
tagfile = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for a tag.
|
||||
* This is a stripped-down version of search().
|
||||
* We don't use search() for several reasons:
|
||||
* - We don't want to blow away any search string we may have saved.
|
||||
* - The various regular-expression functions (from different systems:
|
||||
* regcmp vs. re_comp) behave differently in the presence of
|
||||
* parentheses (which are almost always found in a tag).
|
||||
*/
|
||||
tagsearch()
|
||||
{
|
||||
off_t pos, linepos, forw_raw_line();
|
||||
int linenum;
|
||||
|
||||
pos = (off_t)0;
|
||||
linenum = find_linenum(pos);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
* Get lines until we find a matching one or
|
||||
* until we hit end-of-file.
|
||||
*/
|
||||
if (sigs)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* Read the next line, and save the
|
||||
* starting position of that line in linepos.
|
||||
*/
|
||||
linepos = pos;
|
||||
pos = forw_raw_line(pos);
|
||||
if (linenum != 0)
|
||||
linenum++;
|
||||
|
||||
if (pos == NULL_POSITION)
|
||||
{
|
||||
/*
|
||||
* We hit EOF without a match.
|
||||
*/
|
||||
error("Tag not found");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're using line numbers, we might as well
|
||||
* remember the information we have now (the position
|
||||
* and line number of the current line).
|
||||
*/
|
||||
if (linenums)
|
||||
add_lnum(linenum, pos);
|
||||
|
||||
/*
|
||||
* Test the line to see if we have a match.
|
||||
*/
|
||||
if (strcmp(tagpattern, line) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
jump_loc(linepos);
|
||||
return (0);
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/* from: static char sccsid[] = "@(#)ttyin.c 5.4 (Berkeley) 6/1/90"; */
|
||||
static char *rcsid = "$Id: ttyin.c,v 1.2 1993/11/09 05:14:05 cgd Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines dealing with getting input from the keyboard (i.e. from the user).
|
||||
*/
|
||||
|
||||
#include <less.h>
|
||||
|
||||
static int tty;
|
||||
|
||||
/*
|
||||
* Open keyboard for input.
|
||||
* (Just use file descriptor 2.)
|
||||
*/
|
||||
open_getchr()
|
||||
{
|
||||
tty = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a character from the keyboard.
|
||||
*/
|
||||
getchr()
|
||||
{
|
||||
char c;
|
||||
int result;
|
||||
|
||||
do
|
||||
{
|
||||
result = iread(tty, &c, 1);
|
||||
if (result == READ_INTR)
|
||||
return (READ_INTR);
|
||||
if (result < 0)
|
||||
{
|
||||
/*
|
||||
* Don't call error() here,
|
||||
* because error calls getchr!
|
||||
*/
|
||||
quit();
|
||||
}
|
||||
} while (result != 1);
|
||||
return (c & 0177);
|
||||
}
|
Loading…
Reference in New Issue
Block a user