1 /****************************************************************************
2 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 * view.c -- a silly little viewer program
31 * written by Eric S. Raymond <esr@snark.thyrsus.com> December 1994
32 * to test the scrolling code in ncurses.
34 * modified by Thomas Dickey <dickey@clark.net> July 1995 to demonstrate
35 * the use of 'resizeterm()', and May 2000 to illustrate wide-character
38 * Takes a filename argument. It's a simple file-viewer with various
39 * scroll-up and scroll-down commands.
41 * n -- scroll one line forward
42 * p -- scroll one line back
44 * Either command accepts a numeric prefix interpreted as a repeat count.
45 * Thus, typing `5n' should scroll forward 5 lines in the file.
47 * The way you can tell this is working OK is that, in the trace file,
48 * there should be one scroll operation plus a small number of line
49 * updates, as opposed to a whole-page update. This means the physical
50 * scroll operation worked, and the refresh() code only had to do a
53 * $Id: view.c,v 1.81 2010/11/14 01:06:02 tom Exp $
56 #include <test.priv.h>
60 #undef CTRL /* conflict on AIX 5.2 with <sys/ioctl.h> */
65 #if !defined(__MINGW32__)
70 #if !defined(sun) || !HAVE_TERMIOS_H
72 # include <sys/ioctl.h>
78 /* This is needed to compile 'struct winsize' */
80 #include <sys/stream.h>
85 #if HAVE_MBTOWC && HAVE_MBLEN
86 #define reset_mbytes(state) IGNORE_RC(mblen(NULL, 0)), IGNORE_RC(mbtowc(NULL, NULL, 0))
87 #define count_mbytes(buffer,length,state) mblen(buffer,length)
88 #define check_mbytes(wch,buffer,length,state) \
89 (int) mbtowc(&wch, buffer, length)
91 #elif HAVE_MBRTOWC && HAVE_MBRLEN
92 #define reset_mbytes(state) init_mb(state)
93 #define count_mbytes(buffer,length,state) mbrlen(buffer,length,&state)
94 #define check_mbytes(wch,buffer,length,state) \
95 (int) mbrtowc(&wch, buffer, length, &state)
99 #endif /* USE_WIDEC_SUPPORT */
101 static RETSIGTYPE
finish(int sig
) GCC_NORETURN
;
102 static void show_all(const char *tag
);
104 #if defined(SIGWINCH) && defined(TIOCGWINSZ) && HAVE_RESIZE_TERM
111 static RETSIGTYPE
adjust(int sig
);
112 static int interrupted
;
115 static bool waiting
= FALSE
;
116 static int shift
= 0;
117 static bool try_color
= FALSE
;
120 static NCURSES_CH_T
**vec_lines
;
121 static NCURSES_CH_T
**lptr
;
122 static int num_lines
;
127 static const char *msg
[] =
129 "Usage: view [options] file"
132 ," -c use color if terminal supports it"
133 ," -i ignore INT, QUIT, TERM signals"
134 ," -n NUM specify maximum number of lines (default 1000)"
135 #if defined(KEY_RESIZE)
136 ," -r use old-style sigwinch handler rather than KEY_RESIZE"
139 ," -t trace screen updates"
140 ," -T NUM specify trace mask"
144 for (n
= 0; n
< SIZEOF(msg
); n
++)
145 fprintf(stderr
, "%s\n", msg
[n
]);
146 ExitProgram(EXIT_FAILURE
);
150 ch_len(NCURSES_CH_T
* src
)
153 #if USE_WIDEC_SUPPORT
157 #if USE_WIDEC_SUPPORT
159 TEST_CCHAR(src
, count
, {
175 * Allocate a string into an array of chtype's. If UTF-8 mode is
176 * active, translate the string accordingly.
178 static NCURSES_CH_T
*
181 unsigned len
= (unsigned) strlen(src
);
182 NCURSES_CH_T
*dst
= typeMalloc(NCURSES_CH_T
, len
+ 1);
184 #if USE_WIDEC_SUPPORT
185 wchar_t wstr
[CCHARW_MAX
+ 1];
193 #endif /* USE_WIDEC_SUPPORT */
195 #if USE_WIDEC_SUPPORT
198 for (j
= k
= 0; j
< len
; j
++) {
199 #if USE_WIDEC_SUPPORT
200 rc
= (size_t) check_mbytes(wch
, src
+ j
, len
- j
, state
);
201 if (rc
== (size_t) -1 || rc
== (size_t) -2)
204 if ((width
= wcwidth(wch
)) < 0)
206 if ((width
> 0 && l
> 0) || l
== CCHARW_MAX
) {
209 if (setcchar(dst
+ k
, wstr
, 0, 0, NULL
) != OK
)
213 if (width
== 0 && l
== 0)
217 dst
[k
++] = (chtype
) UChar(src
[j
]);
220 #if USE_WIDEC_SUPPORT
223 if (setcchar(dst
+ k
, wstr
, 0, 0, NULL
) == OK
)
227 setcchar(dst
+ k
, wstr
, 0, 0, NULL
);
235 main(int argc
, char *argv
[])
242 NCURSES_CH_T
**olptr
;
245 bool got_number
= FALSE
;
247 bool nonposix_resize
= FALSE
;
249 const char *my_label
= "Input";
251 setlocale(LC_ALL
, "");
253 #ifndef NCURSES_VERSION
255 * We know ncurses will catch SIGINT if we don't establish our own handler.
256 * Other versions of curses may/may not catch it.
258 (void) signal(SIGINT
, finish
); /* arrange interrupts to terminate */
261 while ((i
= getopt(argc
, argv
, "cin:rtT:")) != -1) {
270 if ((MAXLINES
= atoi(optarg
)) < 1 ||
276 nonposix_resize
= TRUE
;
281 trace((unsigned) atoi(optarg
));
291 if (optind
+ 1 != argc
)
294 if ((vec_lines
= typeCalloc(NCURSES_CH_T
*, (size_t) MAXLINES
+ 2)) == 0)
297 assert(vec_lines
!= 0);
299 fname
= argv
[optind
];
300 if ((fp
= fopen(fname
, "r")) == 0) {
302 ExitProgram(EXIT_FAILURE
);
306 (void) signal(SIGWINCH
, adjust
); /* arrange interrupts to resize */
310 for (lptr
= &vec_lines
[0]; (lptr
- vec_lines
) < MAXLINES
; lptr
++) {
311 char temp
[BUFSIZ
], *s
, *d
;
314 if (fgets(buf
, sizeof(buf
), fp
) == 0)
317 /* convert tabs so that shift will work properly */
318 for (s
= buf
, d
= temp
, col
= 0; (*d
= *s
) != '\0'; s
++) {
322 } else if (*d
== '\t') {
324 while ((d
- temp
) != col
)
327 #if USE_WIDEC_SUPPORT
330 if (isprint(UChar(*d
))) {
334 sprintf(d
, "\\%03o", UChar(*s
));
336 col
= (int) (d
- temp
);
340 *lptr
= ch_dup(temp
);
343 num_lines
= (int) (lptr
- vec_lines
);
345 (void) initscr(); /* initialize the curses library */
346 keypad(stdscr
, TRUE
); /* enable keyboard mapping */
347 (void) nonl(); /* tell curses not to do NL->CR/NL on output */
348 (void) cbreak(); /* take input chars one at a time, no wait for \n */
349 (void) noecho(); /* don't echo input */
350 nodelay(stdscr
, TRUE
);
351 idlok(stdscr
, TRUE
); /* allow use of insert/delete line */
356 init_pair(my_pair
, COLOR_WHITE
, COLOR_BLUE
);
357 bkgd(COLOR_PAIR(my_pair
));
374 my_label
= "interrupt";
380 if ((c
< 127) && isdigit(c
)) {
382 MvPrintw(0, 0, "Count: ");
386 value
= 10 * value
+ (c
- '0');
391 if (got_number
&& value
) {
398 my_label
= keyname(c
);
403 for (i
= 0; i
< n
; i
++)
404 if ((lptr
- vec_lines
) < (num_lines
- LINES
+ 1))
408 scrl((int) (lptr
- olptr
));
414 for (i
= 0; i
< n
; i
++)
415 if (lptr
> vec_lines
)
419 scrl((int) (lptr
- olptr
));
429 if (num_lines
> LINES
)
430 lptr
= vec_lines
+ num_lines
- LINES
+ 1;
454 case KEY_RESIZE
: /* ignore this; ncurses will repaint */
459 halfdelay(my_delay
= n
);
461 nodelay(stdscr
, FALSE
);
466 nodelay(stdscr
, TRUE
);
477 if (c
>= KEY_MIN
|| (c
> 0 && !isdigit(c
))) {
483 finish(0); /* we're done */
491 if (vec_lines
!= 0) {
493 for (n
= 0; n
< num_lines
; ++n
) {
499 ExitProgram(sig
!= 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
504 * This uses functions that are "unsafe", but it seems to work on SunOS.
505 * Usually: the "unsafe" refers to the functions that POSIX lists which may be
506 * called from a signal handler. Those do not include buffered I/O, which is
507 * used for instance in wrefresh(). To be really portable, you should use the
508 * KEY_RESIZE return (which relies on ncurses' sigwinch handler).
510 * The 'wrefresh(curscr)' is needed to force the refresh to start from the top
511 * of the screen -- some xterms mangle the bitmap while resizing.
516 if (waiting
|| sig
== 0) {
519 if (ioctl(fileno(stdout
), TIOCGWINSZ
, &size
) == 0) {
520 resize_term(size
.ws_row
, size
.ws_col
);
522 show_all(sig
? "SIGWINCH" : "interrupt");
528 (void) signal(SIGWINCH
, adjust
); /* some systems need this */
530 #endif /* CAN_RESIZE */
533 show_all(const char *tag
)
541 sprintf(temp
, "%.20s (%3dx%3d) col %d ", tag
, LINES
, COLS
, shift
);
542 i
= (int) strlen(temp
);
543 if ((i
+ 7) < (int) sizeof(temp
)) {
544 sprintf(temp
+ i
, "view %.*s",
545 (int) (sizeof(temp
) - 7 - (size_t) i
),
550 sprintf(temp
, "view %.*s", (int) sizeof(temp
) - 7, fname
);
553 printw("%.*s", COLS
, temp
);
555 this_time
= time((time_t *) 0);
556 strcpy(temp
, ctime(&this_time
));
557 if ((i
= (int) strlen(temp
)) != 0) {
559 if (move(0, COLS
- i
- 2) != ERR
)
563 scrollok(stdscr
, FALSE
); /* prevent screen from moving */
564 for (i
= 1; i
< LINES
; i
++) {
566 printw("%3ld:", (long) (lptr
+ i
- vec_lines
));
568 if ((s
= lptr
[i
- 1]) != 0) {
571 #if USE_WIDEC_SUPPORT
572 add_wchstr(s
+ shift
);
577 #if defined(NCURSES_VERSION) || defined(HAVE_WCHGAT)
579 wchgat(stdscr
, -1, A_NORMAL
, my_pair
, NULL
);
583 setscrreg(1, LINES
- 1);
584 scrollok(stdscr
, TRUE
);