bbcecf6bb97f51244d8aa7f0b7749323176af832
[ncurses.git] / test / view.c
1 /*
2  * view.c -- a silly little viewer program
3  *
4  * written by Eric S. Raymond <esr@snark.thyrsus.com> December 1994
5  * to test the scrolling code in ncurses.
6  *
7  * modified by Thomas Dickey <dickey@clark.net> July 1995 to demonstrate
8  * the use of 'resizeterm()'.
9  *
10  * Takes a filename argument.  It's a simple file-viewer with various 
11  * scroll-up and scroll-down commands.
12  *
13  * n    -- scroll one line forward
14  * p    -- scroll one line back
15  *
16  * Either command accepts a numeric prefix interpreted as a repeat count.
17  * Thus, typing `5n' should scroll forward 5 lines in the file.
18  *
19  * The way you can tell this is working OK is that, in the trace file,
20  * there should be one scroll operation plus a small number of line
21  * updates, as opposed to a whole-page update.  This means the physical
22  * scroll operation worked, and the refresh() code only had to do a
23  * partial repaint.
24  *
25  * $Id: view.c,v 1.20 1997/04/26 18:16:38 tom Exp $
26  */
27
28 #include <test.priv.h>
29
30 #include <string.h>
31 #include <ctype.h>
32 #include <signal.h>
33
34 #if HAVE_TERMIOS_H
35 # include <termios.h>
36 #else
37 # include <sgtty.h>
38 #endif
39
40 #if !defined(sun) || !HAVE_TERMIOS_H
41 # if HAVE_SYS_IOCTL_H
42 #  include <sys/ioctl.h>
43 # endif
44 #endif
45
46 /* This is needed to compile 'struct winsize' */
47 #if SYSTEM_LOOKS_LIKE_SCO
48 #include <sys/stream.h>
49 #include <sys/ptem.h>
50 #endif
51  
52 #define MAXLINES        256        /* most lines we can handle */
53
54 static void finish(int sig) GCC_NORETURN;
55 static void show_all(void);
56  
57 #if defined(SIGWINCH) && defined(TIOCGWINSZ) && defined(NCURSES_VERSION)
58 #define CAN_RESIZE 1
59 #else
60 #define CAN_RESIZE 0
61 #endif
62
63 #if CAN_RESIZE
64 static RETSIGTYPE adjust(int sig);
65 static int          interrupted;
66 #endif
67
68 static int          waiting;
69 static int          shift;
70
71 static char        *fname;
72 static char        *lines[MAXLINES];
73 static char        **lptr;
74
75 #if !HAVE_STRDUP
76 static char *strdup (char *s)
77 {
78   char *p;
79
80   p = malloc(strlen(s)+1);
81   if (p)
82     strcpy(p,s);
83   return(p);
84 }
85 #endif /* not HAVE_STRDUP */
86
87 int main(int argc, char *argv[])
88 {
89 FILE        *fp;
90 char        buf[BUFSIZ];
91 int         i;
92 char        **olptr;
93 int         done = FALSE;
94
95 #ifdef TRACE
96     trace(TRACE_UPDATE);
97 #endif
98
99     if (argc != 2) {
100         fprintf(stderr, "usage: view file\n");
101         return EXIT_FAILURE;
102     } else {
103         fname = argv[1];
104         if ((fp = fopen(fname, "r")) == (FILE *)NULL) {
105             perror(fname);
106             return EXIT_FAILURE;
107         }
108     }
109
110     (void) signal(SIGINT, finish);      /* arrange interrupts to terminate */
111 #if CAN_RESIZE
112     (void) signal(SIGWINCH, adjust);    /* arrange interrupts to resize */
113 #endif
114
115     (void) initscr();      /* initialize the curses library */
116     keypad(stdscr, TRUE);  /* enable keyboard mapping */
117     (void) nonl();         /* tell curses not to do NL->CR/NL on output */
118     (void) cbreak();       /* take input chars one at a time, no wait for \n */
119     (void) noecho();       /* don't echo input */
120     idlok(stdscr, TRUE);   /* allow use of insert/delete line */
121
122     /* slurp the file */
123     for (lptr = &lines[0]; fgets(buf, BUFSIZ, fp) != (char *)NULL; lptr++) {
124         char temp[BUFSIZ], *s, *d;
125         int  col;
126
127         if (lptr - lines >= MAXLINES) {
128             endwin();
129             (void) fprintf(stderr, "%s: %s is too large\n", argv[0], argv[1]);
130             return EXIT_FAILURE;
131         }
132
133         /* convert tabs so that shift will work properly */
134         for (s = buf, d = temp, col = 0; (*d = *s) != '\0'; s++) {
135             if (*d == '\n') {
136                 *d = '\0';
137                 break;
138             } else if (*d == '\t') {
139                 col = (col | 7) + 1;
140                 while ((d-temp) != col)
141                     *d++ = ' ';
142             } else if (isprint(*d)) {
143                 col++;
144                 d++;
145             } else {
146                 sprintf(d, "\\%03o", *s);
147                 d += strlen(d);
148                 col = (d - temp);
149             }
150         }
151         *lptr = strdup(temp);
152     }
153     (void) fclose(fp);
154
155     lptr = lines;
156     while (!done) {
157         int n, c;
158         bool explicit;
159
160         show_all();
161
162         explicit = FALSE;
163         n = 0;
164         for (;;) {
165 #if CAN_RESIZE
166             if (interrupted)
167                 adjust(0);
168 #endif
169             waiting = TRUE;
170             c = getch();
171             waiting = FALSE;
172             if (c < 127 && isdigit(c)) {
173                 n = 10 * n + (c - '0');
174                 explicit = TRUE;
175             } else
176                 break;
177         }
178         if (!explicit && n == 0)
179             n = 1;
180
181         switch(c) {
182         case KEY_DOWN:
183         case 'n':
184             olptr = lptr;
185             for (i = 0; i < n; i++) 
186                 if (lptr + LINES < lines + MAXLINES && lptr[LINES + 1]) 
187                     lptr++;
188                 else
189                     break;
190             wscrl(stdscr, lptr - olptr);
191             break;
192
193         case KEY_UP:
194         case 'p':
195             olptr = lptr;
196             for (i = 0; i < n; i++) 
197                 if (lptr > lines)
198                     lptr--;
199                 else
200                     break;
201             wscrl(stdscr, lptr - olptr);
202             break;
203
204         case 'h':
205         case KEY_HOME:
206             lptr = lines;
207             break;
208
209         case 'r':
210         case KEY_RIGHT:
211             shift++;
212             break;
213
214         case 'l':
215         case KEY_LEFT:
216             if (shift)
217                 shift--;
218             else
219                 beep();
220             break;
221
222         case 'q':
223             done = TRUE;
224             break;
225
226         default:
227             beep();
228         }
229     }
230
231     finish(0);               /* we're done */
232 }
233
234 static RETSIGTYPE finish(int sig)
235 {
236     endwin();
237     exit(sig != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
238 }
239
240 #if CAN_RESIZE
241 /*
242  * This uses functions that are "unsafe", but it seems to work on SunOS and
243  * Linux.  The 'wrefresh(curscr)' is needed to force the refresh to start from
244  * the top of the screen -- some xterms mangle the bitmap while resizing.
245  */
246 static RETSIGTYPE adjust(int sig)
247 {
248         if (waiting || sig == 0) {
249         struct winsize size;
250
251                 if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) {
252                         resizeterm(size.ws_row, size.ws_col);
253                         beep();
254                         wrefresh(curscr);       /* Linux needs this */
255                         show_all();
256                 }
257                 interrupted = FALSE;
258         } else {
259                 interrupted = TRUE;
260         }
261         (void) signal(SIGWINCH, adjust);        /* some systems need this */
262 }
263 #endif  /* CAN_RESIZE */
264
265 static void show_all(void)
266 {
267         int i;
268         char temp[BUFSIZ];
269         char *s;
270
271 #if CAN_RESIZE
272         sprintf(temp, "(%3dx%3d) col %d ", LINES, COLS, shift);
273         i = strlen(temp);
274         sprintf(temp+i, "view %.*s", (int)(sizeof(temp)-7-i), fname);
275 #else
276         sprintf(temp, "view %.*s", (int)sizeof(temp)-7, fname);
277 #endif
278         move(0,0);
279         printw("%.*s", COLS, temp);
280         clrtoeol();
281
282         scrollok(stdscr, FALSE); /* prevent screen from moving */
283         for (i = 1; i < LINES; i++) {
284             move(i, 0);
285             if ((s = lptr[i-1]) != 0 && (int)strlen(s) > shift)
286                 printw("%3d:%.*s", lptr+i-lines, COLS-4, s + shift);
287             else
288                 printw("%3d:", lptr+i-lines);
289             clrtoeol();
290         }
291         setscrreg(1, LINES-1);
292         scrollok(stdscr, TRUE);
293         refresh();
294 }
295
296 /* view.c ends here */
297