4693161282e7428d36d540f62cb563c554b81ed1
[oweals/busybox.git] / util-linux / more.c
1 /*
2  * Mini more implementation for busybox
3  *
4  *
5  * Copyright (C) 1999 by Lineo, inc.
6  * Blended by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7  * based on the original more implementation and code from the Debian 
8  * boot-floppies team.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  */
25
26
27 /* Turning this off makes things a bit smaller (and less pretty) */
28 #define BB_FEATURE_USE_TERMIOS
29 /* Turning this off makes things a bit smaller (and less pretty) */
30 #define BB_FEATURE_AUTOWIDTH
31
32
33
34 #include "internal.h"
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <sys/ioctl.h>
39
40 static const char more_usage[] = "[file ...]";
41
42 /* ED: sparc termios is broken: revert back to old termio handling. */
43 #ifdef BB_FEATURE_USE_TERMIOS
44
45 #if #cpu(sparc)
46 #      define USE_OLD_TERMIO
47 #      include <termio.h>
48 #      define termios termio
49 #      define stty(fd,argp) ioctl(fd,TCSETAF,argp)
50 #else
51 #      include <termios.h>
52 #      define stty(fd,argp) tcsetattr(fd,TCSANOW,argp)
53 #endif
54
55     FILE *cin;
56     struct termios initial_settings, new_settings;
57
58     void gotsig(int sig) { 
59             stty(fileno(cin), &initial_settings);
60             fprintf(stdout, "\n");
61             exit( TRUE);
62     }
63 #endif
64
65
66
67 #define TERMINAL_WIDTH  79      /* not 80 in case terminal has linefold bug */
68 #define TERMINAL_HEIGHT 24
69
70
71 #if defined BB_FEATURE_AUTOWIDTH && ! defined USE_OLD_TERMIO
72 static int terminal_width = 0, terminal_height = 0;
73 #else
74 #define terminal_width  TERMINAL_WIDTH
75 #define terminal_height TERMINAL_HEIGHT
76 #endif
77
78
79
80 extern int more_main(int argc, char **argv)
81 {
82     int c, lines=0, input=0;
83     int next_page=0;
84     struct stat st;     
85     FILE *file;
86 #ifdef BB_FEATURE_AUTOWIDTH
87     struct winsize win;
88 #endif
89
90     argc--;
91     argv++;
92
93     if ( argc > 0 && (strcmp(*argv,"--help")==0 || strcmp(*argv,"-h")==0) ) {
94         usage (more_usage);
95     }
96     do {
97         if (argc==0) {
98             file = stdin;
99         }
100         else
101             file = fopen(*argv, "r");
102
103         if (file == NULL) {
104             perror(*argv);
105             exit(FALSE);
106         }
107         fstat(fileno(file), &st);
108
109 #ifdef BB_FEATURE_USE_TERMIOS
110         cin = fopen("/dev/tty", "r");
111         if (!cin)
112             cin = fopen("/dev/console", "r");
113 #ifdef USE_OLD_TERMIO
114         ioctl(fileno(cin),TCGETA,&initial_settings);
115 #else
116         tcgetattr(fileno(cin),&initial_settings);
117 #endif
118         new_settings = initial_settings;
119         new_settings.c_lflag &= ~ICANON;
120         new_settings.c_lflag &= ~ECHO;
121         stty(fileno(cin), &new_settings);
122
123 #ifdef BB_FEATURE_AUTOWIDTH     
124         ioctl(STDOUT_FILENO, TIOCGWINSZ, &win);
125         if (win.ws_row > 4) 
126             terminal_height = win.ws_row - 2;
127         if (win.ws_col > 0) 
128             terminal_width = win.ws_col - 1;
129 #endif
130
131         (void) signal(SIGINT, gotsig);
132         (void) signal(SIGQUIT, gotsig);
133         (void) signal(SIGTERM, gotsig);
134
135 #endif
136         while ((c = getc(file)) != EOF) {
137             if ( next_page ) {
138                 int len=0;
139                 next_page = 0;
140                 lines=0;
141                 len = fprintf(stdout, "--More-- ");
142                 if (file != stdin) {
143                     len += fprintf(stdout, "(%d%% of %ld bytes)", 
144                         (int) (100*( (double) ftell(file) / (double) st.st_size )),
145                         st.st_size);
146                 }
147                 len += fprintf(stdout, "%s",
148 #ifdef BB_FEATURE_USE_TERMIOS
149                         ""
150 #else
151                         "\n"
152 #endif
153                         );
154
155                 fflush(stdout);
156                 input = getc( cin);
157
158 #ifdef BB_FEATURE_USE_TERMIOS
159                 /* Erase the "More" message */
160                 while(--len >= 0)
161                     putc('\b', stdout);
162                 while(++len <= terminal_width)
163                     putc(' ', stdout);
164                 while(--len >= 0)
165                     putc('\b', stdout);
166                 fflush(stdout);
167 #endif
168
169             }
170             if (c == '\n' ) {
171                 switch(input) {
172                     case 'q':
173                         goto end;
174                     case '\n':
175                         /* increment by just one line if we are at 
176                          * the end of this line*/
177                         next_page = 1;
178                         break;
179                 }
180                 if ( ++lines == terminal_height )
181                     next_page = 1;
182             }
183             putc(c, stdout);
184         }
185         fclose(file);
186         fflush(stdout);
187
188         argv++;
189     } while (--argc > 0);
190 end:
191 #ifdef BB_FEATURE_USE_TERMIOS
192     gotsig(0);
193 #endif  
194     exit(TRUE);
195 }
196