installer: ../Makefile.inc is included via bsd.init.mk, no need to repeat.
[dragonfly.git] / contrib / ncurses-5.4 / test / view.c
blobce9b9b8719d76590649421fa630eb6b84aeb455c
1 /*
2 * view.c -- a silly little viewer program
4 * written by Eric S. Raymond <esr@snark.thyrsus.com> December 1994
5 * to test the scrolling code in ncurses.
7 * modified by Thomas Dickey <dickey@clark.net> July 1995 to demonstrate
8 * the use of 'resizeterm()', and May 2000 to illustrate wide-character
9 * handling.
11 * Takes a filename argument. It's a simple file-viewer with various
12 * scroll-up and scroll-down commands.
14 * n -- scroll one line forward
15 * p -- scroll one line back
17 * Either command accepts a numeric prefix interpreted as a repeat count.
18 * Thus, typing `5n' should scroll forward 5 lines in the file.
20 * The way you can tell this is working OK is that, in the trace file,
21 * there should be one scroll operation plus a small number of line
22 * updates, as opposed to a whole-page update. This means the physical
23 * scroll operation worked, and the refresh() code only had to do a
24 * partial repaint.
26 * $Id: view.c,v 1.57 2003/05/17 21:58:43 tom Exp $
29 #include <time.h>
31 #include <test.priv.h>
33 #if HAVE_TERMIOS_H
34 # include <termios.h>
35 #else
36 # include <sgtty.h>
37 #endif
39 #if !defined(sun) || !HAVE_TERMIOS_H
40 # if HAVE_SYS_IOCTL_H
41 # include <sys/ioctl.h>
42 # endif
43 #endif
45 #define my_pair 1
47 /* This is needed to compile 'struct winsize' */
48 #if NEED_PTEM_H
49 #include <sys/stream.h>
50 #include <sys/ptem.h>
51 #endif
53 static RETSIGTYPE finish(int sig) GCC_NORETURN;
54 static void show_all(const char *tag);
56 #if defined(SIGWINCH) && defined(TIOCGWINSZ) && HAVE_RESIZE_TERM
57 #define CAN_RESIZE 1
58 #else
59 #define CAN_RESIZE 0
60 #endif
62 #if CAN_RESIZE
63 static RETSIGTYPE adjust(int sig);
64 static int interrupted;
65 #endif
67 static bool waiting = FALSE;
68 static int shift = 0;
69 static bool try_color = FALSE;
71 static char *fname;
72 static NCURSES_CH_T **my_lines;
73 static NCURSES_CH_T **lptr;
75 static void
76 usage(void)
78 static const char *msg[] =
80 "Usage: view [options] file"
81 ,""
82 ,"Options:"
83 ," -c use color if terminal supports it"
84 ," -i ignore INT, QUIT, TERM signals"
85 ," -n NUM specify maximum number of lines (default 1000)"
86 #if defined(KEY_RESIZE)
87 ," -r use old-style sigwinch handler rather than KEY_RESIZE"
88 #endif
89 #ifdef TRACE
90 ," -t trace screen updates"
91 ," -T NUM specify trace mask"
92 #endif
94 size_t n;
95 for (n = 0; n < SIZEOF(msg); n++)
96 fprintf(stderr, "%s\n", msg[n]);
97 ExitProgram(EXIT_FAILURE);
100 static int
101 ch_len(NCURSES_CH_T * src)
103 int result = 0;
104 #if USE_WIDEC_SUPPORT
105 #endif
107 #if USE_WIDEC_SUPPORT
108 while (getcchar(src++, NULL, NULL, NULL, NULL) > 0)
109 result++;
110 #else
111 while (*src++)
112 result++;
113 #endif
114 return result;
118 * Allocate a string into an array of chtype's. If UTF-8 mode is
119 * active, translate the string accordingly.
121 static NCURSES_CH_T *
122 ch_dup(char *src)
124 unsigned len = strlen(src);
125 NCURSES_CH_T *dst = typeMalloc(NCURSES_CH_T, len + 1);
126 unsigned j, k;
127 #if USE_WIDEC_SUPPORT
128 wchar_t wstr[CCHARW_MAX + 1];
129 wchar_t wch;
130 int l = 0;
131 mbstate_t state;
132 size_t rc;
133 int width;
134 #endif
136 #if USE_WIDEC_SUPPORT
137 memset(&state, 0, sizeof(state));
138 #endif
139 for (j = k = 0; j < len; j++) {
140 #if USE_WIDEC_SUPPORT
141 rc = mbrtowc(&wch, src + j, len - j, &state);
142 if (rc == (size_t) -1 || rc == (size_t) -2)
143 break;
144 j += rc - 1;
145 if ((width = wcwidth(wch)) < 0)
146 break;
147 if ((width > 0 && l > 0) || l == CCHARW_MAX) {
148 wstr[l] = L'\0';
149 l = 0;
150 if (setcchar(dst + k, wstr, 0, 0, NULL) != OK)
151 break;
152 ++k;
154 if (width == 0 && l == 0)
155 wstr[l++] = L' ';
156 wstr[l++] = wch;
157 #else
158 dst[k++] = src[j];
159 #endif
161 #if USE_WIDEC_SUPPORT
162 if (l > 0) {
163 wstr[l] = L'\0';
164 if (setcchar(dst + k, wstr, 0, 0, NULL) == OK)
165 ++k;
167 setcchar(dst + k, L"", 0, 0, NULL);
168 #else
169 dst[k] = 0;
170 #endif
171 return dst;
175 main(int argc, char *argv[])
177 int MAXLINES = 1000;
178 FILE *fp;
179 char buf[BUFSIZ];
180 int i;
181 int my_delay = 0;
182 NCURSES_CH_T **olptr;
183 int length = 0;
184 int value = 0;
185 bool done = FALSE;
186 bool got_number = FALSE;
187 #if CAN_RESIZE
188 bool nonposix_resize = FALSE;
189 #endif
190 const char *my_label = "Input";
192 setlocale(LC_ALL, "");
194 #ifndef NCURSES_VERSION
196 * We know ncurses will catch SIGINT if we don't establish our own handler.
197 * Other versions of curses may/may not catch it.
199 (void) signal(SIGINT, finish); /* arrange interrupts to terminate */
200 #endif
202 while ((i = getopt(argc, argv, "cin:rtT:")) != EOF) {
203 switch (i) {
204 case 'c':
205 try_color = TRUE;
206 break;
207 case 'i':
208 signal(SIGINT, SIG_IGN);
209 signal(SIGQUIT, SIG_IGN);
210 signal(SIGTERM, SIG_IGN);
211 break;
212 case 'n':
213 if ((MAXLINES = atoi(optarg)) < 1)
214 usage();
215 break;
216 #if CAN_RESIZE
217 case 'r':
218 nonposix_resize = TRUE;
219 break;
220 #endif
221 #ifdef TRACE
222 case 'T':
223 trace(atoi(optarg));
224 break;
225 case 't':
226 trace(TRACE_CALLS);
227 break;
228 #endif
229 default:
230 usage();
233 if (optind + 1 != argc)
234 usage();
236 if ((my_lines = typeMalloc(NCURSES_CH_T *, MAXLINES + 2)) == 0)
237 usage();
239 fname = argv[optind];
240 if ((fp = fopen(fname, "r")) == 0) {
241 perror(fname);
242 ExitProgram(EXIT_FAILURE);
244 #if CAN_RESIZE
245 if (nonposix_resize)
246 (void) signal(SIGWINCH, adjust); /* arrange interrupts to resize */
247 #endif
249 /* slurp the file */
250 for (lptr = &my_lines[0]; (lptr - my_lines) < MAXLINES; lptr++) {
251 char temp[BUFSIZ], *s, *d;
252 int col;
254 if (fgets(buf, sizeof(buf), fp) == 0)
255 break;
257 /* convert tabs so that shift will work properly */
258 for (s = buf, d = temp, col = 0; (*d = *s) != '\0'; s++) {
259 if (*d == '\n') {
260 *d = '\0';
261 break;
262 } else if (*d == '\t') {
263 col = (col | 7) + 1;
264 while ((d - temp) != col)
265 *d++ = ' ';
266 } else
267 #if USE_WIDEC_SUPPORT
268 col++, d++;
269 #else
270 if (isprint(UChar(*d))) {
271 col++;
272 d++;
273 } else {
274 sprintf(d, "\\%03o", UChar(*s));
275 d += strlen(d);
276 col = (d - temp);
278 #endif
280 *lptr = ch_dup(temp);
282 (void) fclose(fp);
283 length = lptr - my_lines;
285 (void) initscr(); /* initialize the curses library */
286 keypad(stdscr, TRUE); /* enable keyboard mapping */
287 (void) nonl(); /* tell curses not to do NL->CR/NL on output */
288 (void) cbreak(); /* take input chars one at a time, no wait for \n */
289 (void) noecho(); /* don't echo input */
290 nodelay(stdscr, TRUE);
291 idlok(stdscr, TRUE); /* allow use of insert/delete line */
293 if (try_color) {
294 if (has_colors()) {
295 start_color();
296 init_pair(my_pair, COLOR_WHITE, COLOR_BLUE);
297 bkgd(COLOR_PAIR(my_pair));
298 } else {
299 try_color = FALSE;
303 lptr = my_lines;
304 while (!done) {
305 int n, c;
307 if (!got_number)
308 show_all(my_label);
310 n = 0;
311 for (;;) {
312 #if CAN_RESIZE
313 if (interrupted) {
314 adjust(0);
315 my_label = "interrupt";
317 #endif
318 waiting = TRUE;
319 c = getch();
320 waiting = FALSE;
321 if ((c < 127) && isdigit(c)) {
322 if (!got_number) {
323 mvprintw(0, 0, "Count: ");
324 clrtoeol();
326 addch(c);
327 value = 10 * value + (c - '0');
328 got_number = TRUE;
329 } else
330 break;
332 if (got_number && value) {
333 n = value;
334 } else {
335 n = 1;
338 if (c != ERR)
339 my_label = keyname(c);
340 switch (c) {
341 case KEY_DOWN:
342 case 'n':
343 olptr = lptr;
344 for (i = 0; i < n; i++)
345 if ((lptr - my_lines) < (length - LINES + 1))
346 lptr++;
347 else
348 break;
349 wscrl(stdscr, lptr - olptr);
350 break;
352 case KEY_UP:
353 case 'p':
354 olptr = lptr;
355 for (i = 0; i < n; i++)
356 if (lptr > my_lines)
357 lptr--;
358 else
359 break;
360 wscrl(stdscr, lptr - olptr);
361 break;
363 case 'h':
364 case KEY_HOME:
365 lptr = my_lines;
366 break;
368 case 'e':
369 case KEY_END:
370 if (length > LINES)
371 lptr = my_lines + length - LINES + 1;
372 else
373 lptr = my_lines;
374 break;
376 case 'r':
377 case KEY_RIGHT:
378 shift += n;
379 break;
381 case 'l':
382 case KEY_LEFT:
383 shift -= n;
384 if (shift < 0) {
385 shift = 0;
386 beep();
388 break;
390 case 'q':
391 done = TRUE;
392 break;
394 #ifdef KEY_RESIZE
395 case KEY_RESIZE: /* ignore this; ncurses will repaint */
396 break;
397 #endif
398 case 's':
399 if (got_number) {
400 halfdelay(my_delay = n);
401 } else {
402 nodelay(stdscr, FALSE);
403 my_delay = -1;
405 break;
406 case ' ':
407 nodelay(stdscr, TRUE);
408 my_delay = 0;
409 break;
410 case ERR:
411 if (!my_delay)
412 napms(50);
413 break;
414 default:
415 beep();
416 break;
418 if (c >= KEY_MIN || (c > 0 && !isdigit(c))) {
419 got_number = FALSE;
420 value = 0;
424 finish(0); /* we're done */
427 static RETSIGTYPE
428 finish(int sig)
430 endwin();
431 ExitProgram(sig != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
434 #if CAN_RESIZE
436 * This uses functions that are "unsafe", but it seems to work on SunOS and
437 * Linux. Usually: the "unsafe" refers to the functions that POSIX lists
438 * which may be called from a signal handler. Those do not include buffered
439 * I/O, which is used for instance in wrefresh(). To be really portable, you
440 * should use the KEY_RESIZE return (which relies on ncurses' sigwinch
441 * handler).
443 * The 'wrefresh(curscr)' is needed to force the refresh to start from the top
444 * of the screen -- some xterms mangle the bitmap while resizing.
446 static RETSIGTYPE
447 adjust(int sig)
449 if (waiting || sig == 0) {
450 struct winsize size;
452 if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) {
453 resize_term(size.ws_row, size.ws_col);
454 wrefresh(curscr); /* Linux needs this */
455 show_all(sig ? "SIGWINCH" : "interrupt");
457 interrupted = FALSE;
458 } else {
459 interrupted = TRUE;
461 (void) signal(SIGWINCH, adjust); /* some systems need this */
463 #endif /* CAN_RESIZE */
465 static void
466 show_all(const char *tag)
468 int i;
469 char temp[BUFSIZ];
470 NCURSES_CH_T *s;
471 time_t this_time;
473 #if CAN_RESIZE
474 sprintf(temp, "%s (%3dx%3d) col %d ", tag, LINES, COLS, shift);
475 i = strlen(temp);
476 sprintf(temp + i, "view %.*s", (int) (sizeof(temp) - 7 - i), fname);
477 #else
478 sprintf(temp, "view %.*s", (int) sizeof(temp) - 7, fname);
479 #endif
480 move(0, 0);
481 printw("%.*s", COLS, temp);
482 clrtoeol();
483 this_time = time((time_t *) 0);
484 strcpy(temp, ctime(&this_time));
485 if ((i = strlen(temp)) != 0) {
486 temp[--i] = 0;
487 if (move(0, COLS - i - 2) != ERR)
488 printw(" %s", temp);
491 scrollok(stdscr, FALSE); /* prevent screen from moving */
492 for (i = 1; i < LINES; i++) {
493 move(i, 0);
494 printw("%3ld:", (long) (lptr + i - my_lines));
495 clrtoeol();
496 if ((s = lptr[i - 1]) != 0) {
497 int len = ch_len(s);
498 if (len > shift) {
499 #if USE_WIDEC_SUPPORT
500 add_wchstr(s + shift);
501 #else
502 addchstr(s + shift);
503 #endif
505 #if defined(NCURSES_VERSION) || defined(HAVE_WCHGAT)
506 if (try_color)
507 wchgat(stdscr, -1, A_NORMAL, my_pair, NULL);
508 #endif
511 setscrreg(1, LINES - 1);
512 scrollok(stdscr, TRUE);
513 refresh();