/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
*/
/*
** 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
** modified by Hans Spiller, Microsoft to handle \r better July 23, 82
** added ? help command, and -w
**
** vwh 11 Jan 83 M001
** modified to handle x.out magic number and magic number
** byte ordering OTHER than the vax and pdp11.
** JJD 19 Jan 83 M002
** - fix distributed on USENET
** From decvax!ucbvax!dist2 Sun Dec 6 02:58:31 1981
** - fixed bug on terminal with "magic cookie" standout
** sequences.
** JJD 14 Feb 83 M003
** - fix exit status of more
** - Made first letter of "no more" message uppercase
** andyp 03 Aug 83 M004 3.0 upgrade
** - use UCB, rather than XENIX, stty(2).
** andyp 30 Nov 83 M005
** - (thanks to reubenb). Changed frame variable to static, it is
** used as a global buffer. We never saw the bug before because
** of the depth of the stack.
** barrys 03 Jul 84 M006
** - Updated the usage message to include the 's' and 'w' options
** and to make the 'n' option a separate entry (uncommented).
** ericc 26 Dec 84 M007
** - Replaced the constant 0x7fffffffffffffffL with MAXLONG.
** ericc 25 Jul 85 M008
** - made "-r" option display control characters as '^x', as documented.
** - fixed processing of '\b' so that more doesn't terminate when
** the sequence "\b\n" is encountered.
** - changed "Hit Rubout ..." to "Hit Del ...", for ibm keyboards.
** davidby 9 March 1988 Unmarked
** - replaced all locally defined functions with library equivalents,
** - changed from termcap to terminfo
** - included <values.h> for MAXLONG value
** - removed most ifdef code for V6, V7, and BSD
*/
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <curses.h>
#include <term.h>
#include <setjmp.h>
#include <values.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <euc.h>
#include <getwidth.h>
#include <locale.h>
#include <widec.h>
#include <wctype.h>
#include <limits.h>
#include <locale.h>
/* Help file will eventually go in libpath(more.help) on all systems */
#ifdef INGRES
#endif
#ifndef INGRES
#ifndef HELPFILE
#endif
#endif
int dum_opt;
#ifdef SIGTSTP
#endif
int promptlen;
false if we are between files */
char ch;
int fseeko();
struct {
static void wait_eof(void);
static void argscan(char *s);
static void initterm(void);
static int readch(void);
static void prmpt_erase(register int col);
static void kill_line(void);
static void prbuf(register char *s, register int n);
static void doclear(void);
static void set_tty(void);
static void reset_tty(void);
int
{
register FILE *f;
register char *s;
register char *p;
register int ch;
int prnames = 0;
int initopt = 0;
int srchopt = 0;
int clearit = 0;
cw[0] = 1;
scw[0] = 1;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
initterm ();
while (--nfiles > 0) {
}
else if (ch == '+') {
s = *fnames;
if (*++s == '/') {
srchopt++;
*p++ = *s++;
*p = '\0';
}
else {
initopt++;
for (initline = 0; *s != '\0'; s++)
if (isdigit (*s))
--initline;
}
}
else break;
}
/* allow clreol only if cursor_home and clr_eol and clr_eos strings are
* defined, and in that case, make sure we are in noscroll mode
*/
if(clreol)
{
clreol = 0;
}
else noscroll = 1;
}
if (dlines == 0)
if (nfiles > 1)
prnames++;
[-cdflrsuw] [-lines] [+linenumber] [+/pattern] [filename ...].\n")
, argv[0]);
exit(1);
}
else
f = stdin;
if (!no_tty) {
#ifdef SIGTSTP
catch_susp++;
}
#endif
set_tty();
}
if (no_intty) {
if (no_tty)
else {
doclear();
else {
if (clreol)
home ();
else
doclear ();
}
}
if (srchopt) {
if (noscroll)
left--;
}
else if (initopt)
}
else
}
no_intty = 0;
prnames++;
firstf = 0;
}
Currline = 0;
if (firstf) {
firstf = 0;
if (srchopt)
{
if (noscroll)
left--;
}
else if (initopt)
}
}
if (left != 0) {
if (clreol)
home ();
else
doclear ();
if (prnames) {
if (ceol_standout_glitch)
prmpt_erase (0);
if (clreol)
cleareol ();
pr("::::::::::::::");
if (promptlen > 14)
prmpt_erase (14);
printf ("\n");
pr("::::::::::::::\n");
}
if (no_tty)
copy_file (f);
else {
within++;
within = 0;
}
}
fclose(f);
} else
fnum++;
firstf = 0;
}
reset_tty ();
return (exitstat); /*M003*/
}
static void
argscan(char *s)
{
for (dlines = 0; *s != '\0'; s++)
if (isdigit(*s))
else if (*s == 'd')
dum_opt = 1;
else if (*s == 'l')
stop_opt = 0;
else if (*s == 'f')
fold_opt = 0;
else if (*s == 'p')
noscroll++;
else if (*s == 'c')
clreol++;
else if (*s == 's')
ssp_opt = 1;
else if (*s == 'u')
ul_opt = 0;
else if (*s == 'r')
cr_opt = 1;
else if (*s == 'w')
wait_opt = 1;
}
/*
** Check whether the file named by fs is a file which the user may
** access. If it is, return the opened file. Otherwise return NULL.
*/
static FILE *
{
register FILE *f;
int c;
if (clreol)
cleareol ();
return (NULL);
}
return (NULL);
}
return (NULL);
}
*clearfirst = 1;
else {
*clearfirst = 0;
Ungetc (c, f);
}
return (f);
}
/*
** Print out the contents of the file f, one screenful at a time.
*/
static void
{
register int c;
register int nchars;
for (;;) {
{
return;
}
continue;
if (ceol_standout_glitch ||
&& promptlen > 0)
prmpt_erase (0);
/* must clear before drawing line since tabs on some terminals
* do not erase what they tab over.
*/
if (clreol)
cleareol ();
else promptlen = 0;
/* is this needed?
* if (clreol)
* cleareol(); */ /* must clear again in case we wrapped */
putchar('\n');
break;
num_lines--;
}
{
return;
}
clreos ();
Ungetc (c, f);
return;
prmpt_erase (0);
if (clreol)
home();
else
doclear ();
}
}
}
/*
** Come here if a quit signal is received
*/
/*
* sig is put in as a dummy arg to have the compiler not to complain
*/
/* ARGSUSED */
void
{
if (!inwait) {
putchar ('\n');
if (!startup) {
}
else
Pause++;
}
promptlen += 20;
notell = 0;
}
}
/*
** Come here if a signal for a window size change is received
*/
/*ARGSUSED*/
void
{
if (nscroll <= 0)
nscroll = 1;
}
}
}
/*
** Clean up terminal state and exit. Also come here if interrupt signal received
*/
/*
* sig is put in as a dummy arg to have the compiler not to complain
*/
/* ARGSUSED */
void
{
reset_tty ();
if (clreol) {
putchar ('\r');
clreos ();
}
kill_line ();
}
else
}
static void
{
register int c;
putchar(c);
}
/* See whether the last component of the path name "path" is equal to the
** string "string"
*/
int
{
}
static void
{
if (clreol)
cleareol ();
else if (promptlen > 0)
kill_line ();
if (!hard) {
promptlen = 8;
if (clreol)
cleareol ();
}
else if (!no_intty) {
}
if (dum_opt) {
}
}
else
inwait++;
}
/*
* when run from another program or a shell script, it is
* sometimes useful to prevent the next program from scrolling
* us off the screen before we get a chance to read this page.
* -Hans, July 24, 1982
*/
static void
wait_eof(void)
{
if (dum_opt)
readch();
prmpt_erase (0);
}
/*
** Get a logical line
*/
static int
{
register int c;
register char *p;
register int column;
static int colflg;
register int oldcolumn;
int csno;
p = Line;
column = 0;
oldcolumn = 0;
c = Getc (f);
if (colflg && c == '\n') {
Currline++;
c = Getc (f);
}
if (c == EOF) {
if (p > Line) {
*p = '\0';
return (column);
}
return (EOF);
}
if (!csno) {
if (c == '\n') {
/* detect \r\n. -Hans */
p--;
}
Currline++;
break;
}
*p++ = c;
if (c == '\t')
promptlen = 0;
}
else {
*p++ = ' ';
}
}
}
else
column--;
/* this is sort of strange. what was here before was that
\r always set column to zero, and the hack above to
detect \r\n didnt exist. the net effect is to make
the current line be overwritten by the prompt if it
had a \r at the end, and the line start after the \r
otherwise. I suppose this is useful for overstriking
on hard copy terminals, but not on anything glass
-Hans */
else if ((c == '\r') && !cr_opt) {
column = 0;
}
else if (c == '\f' && stop_opt) {
p[-1] = '^';
*p++ = 'L';
column += 2;
Pause++;
}
else if (c == EOF) {
return (column);
}
p[-1] = '^';
*p++ = c | ('A' - 1);
column += 2;
} /* M008 end */
else if (c >= ' ' && c != RUBOUT)
column++;
} /* end of code set 0 */
else {
column++;
*p++ = ' ';
}
Ungetc(c,f);
} else {
int i;
*p++ = c;
*p++ = Getc(f);
}
} /* end of codeset 1 ~ 3 */
c = Getc (f);
}
if (!Wrap) {
*p++ = '\n';
}
}
*p++ = '\n'; /* simulate normal wrap */
}
*p = 0;
return (column);
}
/*
** Erase the rest of the prompt, assuming we are starting at column col.
*/
static void
{
if (promptlen == 0)
return;
if (hard) {
putchar ('\n');
}
else {
if (col == 0)
putchar ('\r');
else
putchar (' ');
}
promptlen = 0;
}
/*
** Erase the current line entirely
*/
static void
kill_line(void)
{
prmpt_erase (0);
}
/* Print a buffer of n characters */
static void
prbuf(register char *s, register int n)
{
char c; /* next ouput character */
while (--n >= 0)
if (!ul_opt)
putchar (*s++);
else {
if (n >= 2 && s[0] == '_' && s[1] == '\b') {
n -= 2;
s += 2;
c = *s++;
state = 1;
} else if (n >= 2 && s[1] == '\b' && s[2] == '_') {
n -= 2;
c = *s++;
s += 2;
state = 1;
} else {
c = *s++;
state = 0;
}
putchar(c);
if (state && underline_char) {
}
}
/*
* M002
* You don't want to stay in standout mode at the end of the line;
* on some terminals, this will leave all of the remaining blank
* space on the line in standout mode.
*/
pstate = 0; /*M002*/
} /*M002*/
}
/*
** Clear the screen
*/
static void
doclear(void)
{
if (clear_screen && !hard) {
/* Put out carriage return so that system doesn't
** get confused by escape sequences when expanding tabs
*/
putchar ('\r');
promptlen = 0;
}
}
static int lastcolon;
/*
** 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.
*/
static off_t
{
register int c;
char colonch;
int done;
char *loc;
done = 0;
if (!errors)
else
errors = 0;
for (;;) {
lastp++;
if (lastcmd == ':')
}
kill_line ();
continue;
}
}
switch (comchar) {
case ':':
if (retval >= 0)
done++;
break;
case 'b':
case ctrl('B'):
{
if (no_intty) {
return (-1);
}
putchar ('\r');
prmpt_erase (0);
printf ("\n");
if (clreol)
cleareol ();
if (nlines > 1)
pr ("s\n");
else
pr ("\n");
if (clreol)
cleareol ();
pr ("\n");
if (! noscroll)
--initline;
Currline = 0; /* skiplns() will make Currline correct */
if (! noscroll) {
}
else {
}
}
case ' ':
case 'z':
case 'd':
case ctrl('D'):
case RUBOUT:
case 'q':
case 'Q':
end_it(0);
/*NOTREACHED*/
case 's':
case 'f':
if (comchar == 'f')
putchar ('\r');
prmpt_erase (0);
printf ("\n");
if (clreol)
cleareol ();
if (nlines > 1)
pr ("s\n");
else
pr ("\n");
if (clreol)
cleareol ();
pr ("\n");
while (nlines > 0) {
while ((c = Getc (f)) != '\n')
if (c == EOF) {
retval = 0;
done++;
goto endsw;
}
Currline++;
nlines--;
}
case '\n':
if (nlines != 0)
else
nlines = 1;
case '\f':
if (!no_intty) {
doclear ();
}
else {
break;
}
case '\'':
if (!no_intty) {
kill_line ();
}
else {
break;
}
case '=':
kill_line ();
break;
case 'n':
lastp++;
/*FALLTHROUGH*/
case '/':
kill_line ();
pr ("/");
promptlen = 1;
if (lastp) {
}
else {
}
case '!':
break;
case 'h':
case '?':
/*
* First get local help file.
*/
}
break;
case 'v': /* This case should go right before default */
if (!no_intty) {
kill_line ();
cmdbuf[0] = '+';
break;
}
default:
if (dum_opt) {
kill_line ();
}
else
break;
}
if (done) break;
}
putchar ('\r');
inwait = 0;
notell++;
return (retval);
}
char ch;
/*
* Execute a colon-prefixed command.
* Returns <0 if not a command that should cause
* more of the file to be printed.
*/
static int
{
if (cmd == 0)
else
switch (ch) {
case 'f':
kill_line ();
if (!no_intty)
else
return (-1);
case 'n':
if (nlines == 0) {
end_it(0);
nlines++;
}
putchar ('\r');
prmpt_erase (0);
return (0);
case 'p':
if (no_intty) {
return (-1);
}
putchar ('\r');
prmpt_erase (0);
if (nlines == 0)
nlines++;
return (0);
case '!':
return (-1);
case 'q':
case 'Q':
end_it(0);
default:
return (-1);
}
}
/*
** Read a decimal number from the terminal. Set cmd to the non-digit which
** terminates the number.
*/
static int
{
register int i;
for (;;) {
i = 0;
break;
i = 0;
} else {
break;
}
}
return (i);
}
static void
{
kill_line ();
pr ("!");
promptlen = 1;
if (lastp)
pr (shell_line);
else {
kill_line ();
}
}
promptlen = 0;
shellp = 1;
}
/*
** Search for nth ocurrence of regular expression contained in buf in the file
*/
static void
{
static char *s = NULL;
if (s != NULL)
free(s);
if (*buf != '\0') {
else
} else {
}
} else {
if (s == NULL)
}
lncount = 0;
lncount++;
if (--n == 0) {
{
pr ("\n");
if (clreol)
cleareol ();
}
if (!no_intty) {
if (noscroll)
if (clreol) {
home ();
cleareol ();
}
else
doclear ();
}
else {
kill_line ();
if (noscroll)
if (clreol) {
home ();
cleareol ();
} else
doclear ();
putchar ('\n');
}
break;
}
}
if (!no_intty) {
}
else {
end_it (0);
}
}
}
static void
{
int count;
reset_tty ();
sleep (5);
if (id == 0) {
if (no_intty) { /*M002*/
close(0); /*M002*/
} /*M002*/
count = 0;
do {
#ifndef lint
#else
#endif
count++;
exit (1);
}
#ifdef SIGTSTP
if (catch_susp)
#endif
#ifdef SIGTSTP
if (catch_susp)
#endif
/*
* Since we were ignoring window change signals while we executed
* the command, we must assume the window changed.
*/
(void) chgwinsz(0);
set_tty ();
pr ("------------------------\n");
}
/*
** Skip n lines in the file f
*/
static void
{
register int c;
while (n > 0) {
while ((c = Getc (f)) != '\n')
if (c == EOF)
return;
n--;
Currline++;
}
}
/*
** Skip nskip files in the file list (from the command line). Nskip may be
** negative.
*/
static void
{
if (nskip == 0) return;
if (nskip > 0) {
}
else if (within)
++fnum;
if (fnum < 0)
fnum = 0;
pr ("\n");
if (clreol)
cleareol ();
if (nskip > 0)
else
if (clreol)
cleareol ();
pr ("\n");
--fnum;
}
/*----------------------------- Terminal I/O -------------------------------*/
static void
initterm(void)
{
int erret = 0;
}
else {
hard++; /* Hard copy terminal */
Lpp = 24;
}
noscroll++;
Mcol = 80;
/*
* Set up for underlining: some terminals don't need it;
* underline char sequence which is assumed to move the
* cursor forward one character. If underline sequence
* isn't available, settle for standout sequence.
*/
if (transparent_underline || over_strike)
ul_opt = 0;
ULenter = "";
ULexit = "";
}
}
}
static int
readch(void)
{
char ch;
extern int errno;
end_it(0); /* clean up before exiting */
else
return (ch);
}
static void
{
register char *sptr;
register unsigned char ch;
int *BufferPointer;
int csno;
register int slash = 0;
int maxlen;
char cbuf;
maxlen = 0;
if (!csno) {
if (ch == '\\') {
slash++;
--promptlen;
sptr -= (*--BufferPointer);
--promptlen;
}
continue;
} else {
if (!clr_eol)
}
if (hard) {
putchar ('\n');
} else {
putchar ('\r');
if (clr_eol)
prmpt_erase (1);
promptlen = 1;
}
continue;
}
sptr -= (*--BufferPointer);
}
if (ch != '\\')
slash = 0;
*BufferPointer++ = 1;
promptlen++;
}
promptlen++;
} else
break;
/* end of code set 0 */
} else {
int i;
}
buffer[i]='\0';
}
}
*--sptr = '\0';
}
static int
{
char *in_str;
char *out_str;
char ch;
int changed = 0;
switch (ch) {
case '%':
if (!no_intty) {
>= sizeof (temp))
changed++;
}
else
break;
case '!':
if (!shellp)
changed++;
break;
case '\\':
break;
}
default:
}
*out_str++ = '\0';
return (changed);
}
static void
{
char cbuf;
promptlen++;
}
promptlen++;
}
static void
{
if (clreol)
cleareol ();
else
kill_line ();
if (enter_standout_mode && exit_standout_mode) {
}
else
errors++;
}
static void
set_tty(void)
{
}
static void
reset_tty(void)
{
}
static void
{
register int c;
register char *p;
p = Line;
*p++ = c;
if (c == '\n')
Currline++;
*p = '\0';
}
/* Come here when we get a suspend signal from the terminal */
/*
* sig is put in as a dummy arg to have the compiler not to complain
*/
#ifdef SIGTSTP
/* ARGSUSED */
void
{
/* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
reset_tty ();
/* Send the TSTP signal to suspend our process group */
/* Pause for station break */
/* We're back */
set_tty ();
if (inwait)
}
#endif