d4eb51694ea7a281f17635c4658f08db0838458b
static char *sccsid
= "@(#)more.c 4.11 (Berkeley) 83/03/17";
** more.c - General purpose tty output filter and file perusal program
** by Eric Shienbrood, UC Berkeley
** modified by Geoff Peck, UCB to add underlining, single spacing
** modified by John Foderaro, UCB to add -c and MORE environment variable
/* Help file will eventually go in libpath(more.help) on all systems */
#define HELPFILE libpath(more.help)
#define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m))
#define Ftell(f) file_pos
#define Fseek(f,off) (file_pos=off,fseek(f,off,0))
#define Getc(f) (++file_pos, getc(f))
#define Ungetc(c,f) (--file_pos, ungetc(c,f))
#define stty(fd,argp) ioctl(fd,TIOCSETN,argp)
#define ctrl(letter) ('letter' & 077)
long file_pos
, file_size
;
int fnum
, no_intty
, no_tty
, slow_tty
;
int dum_opt
, dlines
, onquit(), end_it();
int nscroll
= 11; /* Number of lines scrolled by 'd' */
int fold_opt
= 1; /* Fold long lines */
int stop_opt
= 1; /* Stop after form feeds */
int ssp_opt
= 0; /* Suppress white space */
int ul_opt
= 1; /* Underline as best we can */
int Currline
; /* Line we are currently at */
int bad_so
; /* True if overwriting does not turn off standout */
int inwait
, Pause
, errors
;
int within
; /* true if we are within a file,
false if we are between files */
int hard
, dumb
, noscroll
, hardtabs
, clreol
;
int catch_susp
; /* We should catch the SIGTSTP signal */
char **fnames
; /* The list of file names */
int nfiles
; /* Number of files left to process */
char *shell
; /* The name of the shell to use */
int shellp
; /* A previous shell command exists */
char obuf
[BUFSIZ
]; /* stdout buffer */
char Line
[LINSIZ
]; /* Line buffer */
int Lpp
= 24; /* lines per page */
char *Clear
; /* clear screen */
char *eraseln
; /* erase line */
char *Senter
, *Sexit
;/* enter and exit standout mode */
char *ULenter
, *ULexit
; /* enter and exit underline mode */
char *chUL
; /* underline character */
char *chBS
; /* backspace character */
char *Home
; /* go to home */
char *cursorm
; /* cursor movement */
char cursorhome
[40]; /* contains cursor movement to home */
char *EodClr
; /* clear rest of screen */
int Mcol
= 80; /* number of columns */
int Wrap
= 1; /* set if automargins */
extern char PC
; /* pad character */
if(s
= getenv("MORE")) argscan(s
);
if ((ch
= (*++fnames
)[0]) == '-') {
for (++s
, p
= initbuf
; p
< initbuf
+ 79 && *s
!= '\0';)
for (initline
= 0; *s
!= '\0'; s
++)
initline
= initline
*10 + *s
-'0';
/* allow clreol only if Home and eraseln and EodClr strings are
* defined, and in that case, make sure we are in noscroll mode
if ((*Home
== '\0') || (*eraseln
== '\0') || (*EodClr
== '\0'))
dlines
= Lpp
- (noscroll
? 1 : 2);
if (!no_intty
&& nfiles
== 0) {
fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr
);
if (signal (SIGTSTP
, SIG_IGN
) == SIG_DFL
) {
if ((ch
= Getc (f
)) == '\f')
if (noscroll
&& (ch
!= EOF
)) {
search (initbuf
, stdin
, 1);
skiplns (initline
, stdin
);
if ((f
= checkf (fnames
[fnum
], &clearit
)) != NULL
) {
context
.line
= context
.chrctr
= 0;
if (firstf
) setjmp (restore
);
else if (fnum
< nfiles
&& !no_tty
) {
left
= command (fnames
[fnum
], f
);
if ((noscroll
|| clearit
) && (file_size
!= 0x7fffffffffffffffL
))
printf("%s\n", fnames
[fnum
]);
printf("::::::::::::::\n", fnames
[fnum
]);
screen_start
.line
= screen_start
.chrctr
= 0L;
context
.line
= context
.chrctr
= 0L;
for (dlines
= 0; *s
!= '\0'; s
++)
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
dlines
= dlines
*10 + *s
- '0';
** Check whether the file named by fs is an ASCII file which the user may
** access. If it is, return the opened file. Otherwise return NULL.
if (stat (fs
, &stbuf
) == -1) {
if ((stbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
printf("\n*** %s: directory ***\n\n", fs
);
if ((f
=Fopen(fs
, "r")) == NULL
) {
/* Try to see whether it is an ASCII file */
switch ((c
| *f
->_ptr
<< 8) & 0177777) {
printf("\n******** %s: Not a text file ********\n\n", fs
);
if ((file_size
= stbuf
.st_size
) == 0)
file_size
= 0x7fffffffffffffffL
;
** A real function, for the tputs routine in termlib
** Print out the contents of the file f, one screenful at a time.
int length
; /* length of current line */
static int prev_len
= 1; /* length of previous line */
while (num_lines
> 0 && !Pause
) {
if ((nchars
= getline (f
, &length
)) == EOF
)
if (ssp_opt
&& length
== 0 && prev_len
== 0)
if (bad_so
|| (Senter
&& *Senter
== ' ') && promptlen
> 0)
/* must clear before drawing line since tabs on some terminals
* do not erase what they tab over.
erase (nchars
); /* erase () sets promptlen to 0 */
* cleareol(); /* must clear again in case we wrapped *
if (nchars
< Mcol
|| !fold_opt
)
if ((c
= Getc(f
)) == EOF
)
if ((num_lines
= command (NULL
, f
)) == 0)
if (hard
&& promptlen
> 0)
if (noscroll
&& num_lines
>= dlines
)
screen_start
.line
= Currline
;
screen_start
.chrctr
= Ftell (f
);
** Come here if a quit signal is received
signal(SIGQUIT
, SIG_IGN
);
else if (!dum_opt
&& notell
) {
write (2, "[Use q or Q to quit]", 20);
** Clean up terminal state and exit. Also come here if interrupt signal received
else if (!clreol
&& (promptlen
> 0)) {
while ((c
= getc(f
)) != EOF
)
/* Simplified printf function */
while ((ch
= *fmt
++) != '%') {
ccount
+= printd (*argp
);
ccount
+= pr ((char *)*argp
);
** Print an integer as a string of decimal digits,
** returning the length of the print representation.
/* Put the print representation of an integer into a string */
static char bell
= ctrl(G
);
/* See whether the last component of the path name "path" is equal to the
tail
= path
+ strlen(path
);
while (*tail
++ == *string
++)
tputs (Senter
, 1, putch
);
promptlen
+= printf ("(Next file: %s)", filename
);
promptlen
+= printf ("(%d%%)", (int)((file_pos
* 100) / file_size
));
promptlen
+= pr("[Hit space to continue, Rubout to abort]");
if (colflg
&& c
== '\n') {
while (p
< &Line
[LINSIZ
- 1]) {
if (hardtabs
&& column
< promptlen
&& !hard
) {
column
= 1 + (column
| 7);
tputs (eraseln
, 1, putch
);
for (--p
; column
& 7 && p
< &Line
[LINSIZ
- 1]; column
++) {
if (column
>= promptlen
) promptlen
= 0;
column
= 1 + (column
| 7);
else if (c
== '\b' && column
> 0)
else if (c
== '\f' && stop_opt
) {
else if (c
>= ' ' && c
!= RUBOUT
)
if (column
>= Mcol
&& fold_opt
) break;
if (column
>= Mcol
&& Mcol
> 0) {
colflg
= column
== Mcol
&& fold_opt
;
** Erase the rest of the prompt, assuming we are starting at column col.
tputs (eraseln
, 1, putch
);
for (col
= promptlen
- col
; col
> 0; col
--)
** Erase the current line entirely
if (!eraseln
|| dumb
) putchar ('\r');
* force clear to end of line
tputs(eraseln
, 1, putch
);
** Print string and return number of characters
/* Print a buffer of n characters */
char c
; /* next ouput character */
register int state
; /* next output char's UL state */
static int pstate
= 0; /* current terminal UL state (off) */
if (n
>= 2 && s
[0] == '_' && s
[1] == '\b') {
} else if (n
>= 2 && s
[1] == '\b' && s
[2] == '_') {
tputs(state
? ULenter
: ULexit
, 1, putch
);
/* Put out carriage return so that system doesn't
** get confused by escape sequences when expanding tabs
static int lastcmd
, lastarg
, lastp
;
** Read a command and do it. A command consists of an optional integer
** argument followed by the command character. Return the number of lines
** to display in the next screenful. If there is nothing more to display
** in the current file, zero is returned.
char comchar
, cmdbuf
[80], *p
;
#define ret(val) retval=val;done++;break
if (MBIT
== RAW
&& slow_tty
) {
nlines
= number (&comchar
);
if (comchar
== '.') { /* Repeat last command */
if (comchar
== otty
.sg_erase
) {
retval
= colon (filename
, colonch
, nlines
);
if (nlines
== 0) nlines
= dlines
;
else if (comchar
== 'z') dlines
= nlines
;
if (nlines
!= 0) nscroll
= nlines
;
if (nlines
== 0) nlines
++;
printf ("...skipping %d line", nlines
);
while ((c
= Getc (f
)) != '\n')
Fseek (f
, screen_start
.chrctr
);
Currline
= screen_start
.line
;
Fseek (f
, context
.chrctr
);
promptlen
= printd (Currline
);
if (nlines
== 0) nlines
++;
search (NULL
, f
, nlines
); /* Use previous r.e. */
search (cmdbuf
, f
, nlines
);
if ((helpf
= fopen (HELPFILE
, "r")) == NULL
)
error ("Can't open help file");
if (noscroll
) doclear ();
case 'v': /* This case should go right before default */
scanstr (Currline
, &cmdbuf
[1]);
pr ("vi "); pr (cmdbuf
); putchar (' '); pr (fnames
[fnum
]);
execute (filename
, VI
, "vi", cmdbuf
, fnames
[fnum
], 0);
if (MBIT
== RAW
&& slow_tty
) {
* Execute a colon-prefixed command.
* Returns <0 if not a command that should cause
* more of the file to be printed.
colon (filename
, cmd
, nlines
)
promptlen
= printf ("\"%s\" line %d", fnames
[fnum
], Currline
);
promptlen
= printf ("[Not a file] line %d", Currline
);
** Read a decimal number from the terminal. Set cmd to the non-digit which
** terminates the number.
i
= 0; ch
= otty
.sg_kill
;
if (ch
>= '0' && ch
<= '9')
else if (ch
== otty
.sg_kill
)
if (expand (shell_line
, cmdbuf
)) {
promptlen
= printf ("!%s", shell_line
);
execute (filename
, shell
, shell
, "-c", shell_line
, 0);
** Search for nth ocurrence of regular expression contained in buf in the file
long startline
= Ftell (file
);
register long line1
= startline
;
register long line2
= startline
;
register long line3
= startline
;
int saveln
, rv
, re_exec();
context
.line
= saveln
= Currline
;
context
.chrctr
= startline
;
if ((s
= re_comp (buf
)) != 0)
if ((rv
= re_exec (Line
)) == 1)
if (lncount
> 3 || (lncount
> 1 && no_intty
))
Currline
-= (lncount
>= 3 ? 3 : lncount
);
error ("Regular expression botch");
file
->_flag
&= ~_IOEOF
; /* why doesn't fseek do this ??!!??! */
pr ("\nPattern not found\n");
error ("Pattern not found");
execute (filename
, cmd
, args
)
while ((id
= fork ()) < 0)
write (2, "exec failed\n", 12);
signal (SIGINT
, SIG_IGN
);
signal (SIGQUIT
, SIG_IGN
);
signal(SIGTSTP
, SIG_DFL
);
signal (SIGQUIT
, onquit
);
pr ("------------------------\n");
** Skip n lines in the file f
while ((c
= Getc (f
)) != '\n')
** Skip nskip files in the file list (from the command line). Nskip may be
if (fnum
+ nskip
> nfiles
- 1)
nskip
= nfiles
- fnum
- 1;
pr (nskip
> 0 ? "to file " : "back to file ");
/*----------------------------- Terminal I/O -------------------------------*/
if (!(no_tty
= gtty(1, &otty
))) {
if ((term
= getenv("TERM")) && tgetent(buf
, term
) <= 0) {
if (((Lpp
= tgetnum("li")) < 0) || tgetflag("hc")) {
hard
++; /* Hard copy terminal */
if (tailequ (fnames
[0], "page") || !hard
&& tgetflag("ns"))
if ((Mcol
= tgetnum("co")) < 0)
bad_so
= tgetflag ("xs");
eraseln
= tgetstr("ce",&clearptr
);
Clear
= tgetstr("cl", &clearptr
);
Senter
= tgetstr("so", &clearptr
);
Sexit
= tgetstr("se", &clearptr
);
* Set up for underlining: some terminals don't need it;
* others have start/stop sequences, still others have an
* underline char sequence which is assumed to move the
* cursor forward one character. If underline sequence
* isn't available, settle for standout sequence.
if (tgetflag("ul") || tgetflag("os"))
if ((chUL
= tgetstr("uc", &clearptr
)) == NULL
)
if ((ULenter
= tgetstr("us", &clearptr
)) == NULL
&&
(!*chUL
) && (ULenter
= tgetstr("so", &clearptr
)) == NULL
)
if ((ULexit
= tgetstr("ue", &clearptr
)) == NULL
&&
(!*chUL
) && (ULexit
= tgetstr("se", &clearptr
)) == NULL
)
if (padstr
= tgetstr("pc", &clearptr
))
Home
= tgetstr("ho",&clearptr
);
if (Home
== 0 && *Home
== '\0')
if ((cursorm
= tgetstr("cm", &clearptr
)) != NULL
) {
strcpy(cursorhome
, tgoto(cursorm
, 0, 0));
EodClr
= tgetstr("cd", &clearptr
);
if ((shell
= getenv("SHELL")) == NULL
)
no_intty
= gtty(0, &otty
);
slow_tty
= ospeed
< B1200
;
hardtabs
= !(otty
.sg_flags
& XTABS
);
if (MBIT
== CBREAK
|| !slow_tty
)
if (read (2, &ch
, 1) <= 0)
while (sptr
- buf
< nmax
) {
if (promptlen
> maxlen
) maxlen
= promptlen
;
else if ((ch
== otty
.sg_erase
) && !slash
) {
if ((*sptr
< ' ' && *sptr
!= '\n') || *sptr
== RUBOUT
) {
if (!eraseln
) promptlen
= maxlen
;
else if ((ch
== otty
.sg_kill
) && !slash
) {
if (slash
&& (ch
== otty
.sg_kill
|| ch
== otty
.sg_erase
)) {
if ((ch
< ' ' && ch
!= '\n' && ch
!= ESC
) || ch
== RUBOUT
) {
ch
+= ch
== RUBOUT
? -0100 : 0100;
if (ch
!= '\n' && ch
!= ESC
) {
if (!eraseln
) promptlen
= maxlen
;
if (sptr
- buf
>= nmax
- 1)
while ((ch
= *instr
++) != '\0')
strcpy (outstr
, fnames
[fnum
]);
outstr
+= strlen (fnames
[fnum
]);
error ("No previous command to substitute for");
strcpy (outstr
, shell_line
);
outstr
+= strlen (shell_line
);
if (*instr
== '%' || *instr
== '!') {
if ((ch
< ' ' && ch
!= '\n' && ch
!= ESC
) || ch
== RUBOUT
) {
ch
+= ch
== RUBOUT
? -0100 : 0100;
promptlen
+= strlen (mess
);
tputs (Senter
, 1, putch
);
while ((c
= Getc (f
)) != '\n' && c
!= EOF
&& p
- Line
< LINSIZ
- 1)
/* Come here when we get a suspend signal from the terminal */
/* Send the TSTP signal to suspend our process group */
/* Pause for station break */
signal (SIGTSTP
, onsusp
);