busybox/util-linux/more.c
Rob Landley d921b2ecc0 Remove bb_ prefixes from xfuncs.c (and a few other places), consolidate
things like xasprintf() into xfuncs.c, remove xprint_file_by_name() (it only
had one user), clean up lots of #includes...  General cleanup pass.  What I've
been doing for the last couple days.

And it conflicts!  I've removed httpd.c from this checkin due to somebody else
touching that file.  It builds for me.  I have to catch a bus.  (Now you know
why I'm looking forward to Mercurial.)
2006-08-03 15:41:12 +00:00

190 lines
4.5 KiB
C

/* vi: set sw=4 ts=4: */
/*
* Mini more implementation for busybox
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
* Latest version blended together by Erik Andersen <andersen@codepoet.org>,
* based on the original more implementation by Bruce, and code from the
* Debian boot-floppies team.
*
* Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
*
* Licensed under GPLv2 or later, see file License in this tarball for details.
*/
#include "busybox.h"
#ifdef CONFIG_FEATURE_USE_TERMIOS
static int cin_fileno;
#include <termios.h>
#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
#define getTermSettings(fd,argp) tcgetattr(fd, argp);
static struct termios initial_settings, new_settings;
static void set_tty_to_initial_mode(void)
{
setTermSettings(cin_fileno, &initial_settings);
}
static void gotsig(int sig)
{
putchar('\n');
exit(EXIT_FAILURE);
}
#endif /* CONFIG_FEATURE_USE_TERMIOS */
int more_main(int argc, char **argv)
{
int c, lines, input = 0;
int please_display_more_prompt = 0;
struct stat st;
FILE *file;
FILE *cin;
int len, page_height;
int terminal_width;
int terminal_height;
argc--;
argv++;
/* not use inputing from terminal if usage: more > outfile */
if(isatty(STDOUT_FILENO)) {
cin = fopen(CURRENT_TTY, "r");
if (!cin)
cin = xfopen(CONSOLE_DEV, "r");
please_display_more_prompt = 2;
#ifdef CONFIG_FEATURE_USE_TERMIOS
cin_fileno = fileno(cin);
getTermSettings(cin_fileno, &initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
setTermSettings(cin_fileno, &new_settings);
atexit(set_tty_to_initial_mode);
(void) signal(SIGINT, gotsig);
(void) signal(SIGQUIT, gotsig);
(void) signal(SIGTERM, gotsig);
#endif
} else {
cin = stdin;
}
do {
if (argc == 0) {
file = stdin;
} else
file = bb_wfopen(*argv, "r");
if(file==0)
goto loop;
st.st_size = 0;
fstat(fileno(file), &st);
please_display_more_prompt &= ~1;
get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height);
if (terminal_height > 4)
terminal_height -= 2;
if (terminal_width > 0)
terminal_width -= 1;
len=0;
lines = 0;
page_height = terminal_height;
while ((c = getc(file)) != EOF) {
if ((please_display_more_prompt & 3) == 3) {
len = printf("--More-- ");
if (file != stdin && st.st_size > 0) {
#if _FILE_OFFSET_BITS == 64
len += printf("(%d%% of %lld bytes)",
(int) (100 * ((double) ftell(file) /
(double) st.st_size)), (long long)st.st_size);
#else
len += printf("(%d%% of %ld bytes)",
(int) (100 * ((double) ftell(file) /
(double) st.st_size)), (long)st.st_size);
#endif
}
fflush(stdout);
/*
* We've just displayed the "--More--" prompt, so now we need
* to get input from the user.
*/
input = getc(cin);
#ifndef CONFIG_FEATURE_USE_TERMIOS
printf("\033[A"); /* up cursor */
#endif
/* Erase the "More" message */
putc('\r', stdout);
while (--len >= 0)
putc(' ', stdout);
putc('\r', stdout);
len=0;
lines = 0;
page_height = terminal_height;
please_display_more_prompt &= ~1;
if (input == 'q')
goto end;
}
/*
* There are two input streams to worry about here:
*
* c : the character we are reading from the file being "mored"
* input : a character received from the keyboard
*
* If we hit a newline in the _file_ stream, we want to test and
* see if any characters have been hit in the _input_ stream. This
* allows the user to quit while in the middle of a file.
*/
if (c == '\n') {
/* increment by just one line if we are at
* the end of this line */
if (input == '\n')
please_display_more_prompt |= 1;
/* Adjust the terminal height for any overlap, so that
* no lines get lost off the top. */
if (len >= terminal_width) {
int quot, rem;
quot = len / terminal_width;
rem = len - (quot * terminal_width);
if (quot) {
if (rem)
page_height-=quot;
else
page_height-=(quot-1);
}
}
if (++lines >= page_height) {
please_display_more_prompt |= 1;
}
len=0;
}
/*
* If we just read a newline from the file being 'mored' and any
* key other than a return is hit, scroll by one page
*/
putc(c, stdout);
len++;
}
fclose(file);
fflush(stdout);
loop:
argv++;
} while (--argc > 0);
end:
return 0;
}