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
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
26 * $Id: view.c,v 1.2 2007/05/28 15:01:58 blymn Exp $
31 #include <sys/types.h>
34 #define _XOPEN_SOURCE_EXTENDED
48 #endif /* HAVE_WCHAR */
53 #define UChar(c) ((unsigned char)(c))
54 #define SIZEOF(table) (sizeof(table)/sizeof(table[0]))
55 #define typeMalloc(type,n) (type *) malloc((n) * sizeof(type))
61 #define CURSES_CH_T cchar_t
63 #define CURSES_CH_T chtype
64 #endif /* HAVE_WCHAR */
66 static void finish(int sig
);
67 static void show_all(const char *tag
);
70 static bool try_color
= FALSE
;
73 static CURSES_CH_T
**my_lines
;
74 static CURSES_CH_T
**lptr
;
75 static unsigned num_lines
;
77 static void usage(void)
79 static const char *msg
[] = {
80 "Usage: view [options] file"
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"
90 ," -t trace screen updates"
91 ," -T NUM specify trace mask"
95 for (n
= 0; n
< SIZEOF(msg
); n
++)
96 fprintf(stderr
, "%s\n", msg
[n
]);
100 static int ch_len(CURSES_CH_T
* src
)
105 while (getcchar(src
++, NULL
, NULL
, NULL
, NULL
) > 0)
115 * Allocate a string into an array of chtype's. If UTF-8 mode is
116 * active, translate the string accordingly.
118 static CURSES_CH_T
* ch_dup(char *src
)
120 unsigned len
= strlen(src
);
121 CURSES_CH_T
*dst
= typeMalloc(CURSES_CH_T
, len
+ 1);
124 wchar_t wstr
[CCHARW_MAX
+ 1];
133 mbrtowc( NULL
, NULL
, 1, &state
);
135 for (j
= k
= 0; j
< len
; j
++) {
137 rc
= mbrtowc(&wch
, src
+ j
, len
- j
, &state
);
139 syslog( LOG_INFO
, "[ch_dup]mbrtowc() returns %d", rc
);
141 if (rc
== (size_t) -1 || rc
== (size_t) -2)
144 if ((width
= wcwidth(wch
)) < 0)
146 if ((width
> 0 && l
> 0) || l
== CCHARW_MAX
) {
149 if (setcchar(dst
+ k
, wstr
, 0, 0, NULL
) != OK
)
153 if (width
== 0 && l
== 0)
157 syslog( LOG_INFO
, "[ch_dup]wch=%x", wch
);
166 if (setcchar(dst
+ k
, wstr
, 0, 0, NULL
) == OK
)
169 setcchar(dst
+ k
, L
"", 0, 0, NULL
);
176 int main(int argc
, char *argv
[])
187 bool got_number
= FALSE
;
188 const char *my_label
= "Input";
191 #endif /* HAVE_WCHAR */
193 setlocale(LC_ALL
, "");
195 (void) signal(SIGINT
, finish
); /* arrange interrupts to terminate */
197 while ((i
= getopt(argc
, argv
, "cin:rtT:")) != EOF
) {
203 signal(SIGINT
, SIG_IGN
);
204 signal(SIGQUIT
, SIG_IGN
);
205 signal(SIGTERM
, SIG_IGN
);
208 if ((MAXLINES
= atoi(optarg
)) < 1)
223 if (optind
+ 1 != argc
)
226 if ((my_lines
= typeMalloc(CURSES_CH_T
*, MAXLINES
+ 2)) == 0)
229 fname
= argv
[optind
];
230 if ((fp
= fopen(fname
, "r")) == 0) {
237 for (lptr
= &my_lines
[0]; (lptr
- my_lines
) < MAXLINES
; lptr
++) {
238 char temp
[BUFSIZ
], *s
, *d
;
241 if (fgets(buf
, sizeof(buf
), fp
) == 0)
244 /* convert tabs so that shift will work properly */
245 for (s
= buf
, d
= temp
, col
= 0; (*d
= *s
) != '\0'; s
++) {
249 } else if (*d
== '\t') {
251 while ((d
- temp
) != col
)
257 if (isprint(UChar(*d
))) {
261 sprintf(d
, "\\%03o", UChar(*s
));
267 *lptr
= ch_dup(temp
);
271 length
= lptr
- my_lines
;
273 (void) initscr(); /* initialize the curses library */
274 keypad(stdscr
, TRUE
); /* enable keyboard mapping */
275 (void) nonl(); /* tell curses not to do NL->CR/NL on output */
276 (void) cbreak(); /* take input chars one at a time, no wait for \n */
277 (void) noecho(); /* don't echo input */
278 nodelay(stdscr
, TRUE
);
279 idlok(stdscr
, TRUE
); /* allow use of insert/delete line */
284 init_pair(my_pair
, COLOR_WHITE
, COLOR_BLUE
);
285 bkgd(COLOR_PAIR(my_pair
));
299 #endif /* HAVE_WCHAR */
315 else if ( ret
== KEY_CODE_YES
)
316 syslog( LOG_INFO
, "[main]Func key(%x)", c
);
318 syslog( LOG_INFO
, "[main]c=%x", c
);
323 syslog( LOG_INFO
, "[main]c='%c'", c
);
325 #endif /* HAVE_WCHAR */
326 if ((c
< 127) && isdigit(c
)) {
328 mvprintw(0, 0, "Count: ");
332 value
= 10 * value
+ (c
- '0');
337 if (got_number
&& value
) {
345 my_label
= key_name( c
);
351 my_label
= keyname(c
);
352 #endif /* HAVE_WCHAR */
359 #endif /* HAVE_WCHAR */
361 for (i
= 0; i
< n
; i
++)
362 if ((lptr
- my_lines
) < (length
- LINES
+ 1))
366 wscrl(stdscr
, lptr
- olptr
);
374 #endif /* HAVE_WCHAR */
376 for (i
= 0; i
< n
; i
++)
381 wscrl(stdscr
, lptr
- olptr
);
388 #endif /* HAVE_WCHAR */
397 #endif /* HAVE_WCHAR */
400 lptr
= my_lines
+ length
- LINES
+ 1;
409 #endif /* HAVE_WCHAR */
418 #endif /* HAVE_WCHAR */
431 #endif /* HAVE_WCHAR */
444 #endif /* HAVE_WCHAR */
446 halfdelay(my_delay
= n
);
448 nodelay(stdscr
, FALSE
);
456 #endif /* HAVE_WCHAR */
457 nodelay(stdscr
, TRUE
);
465 #endif /* HAVE_WCHAR */
470 if (c
>= KEY_MIN
|| (c
> 0 && !isdigit(c
))) {
476 finish(0); /* we're done */
479 static void finish(int sig
)
482 exit(sig
!= 0 ? 1 : 0 );
485 static void show_all(const char *tag
)
492 sprintf(temp
, "%s (%3dx%3d) col %d ", tag
, LINES
, COLS
, shift
);
494 sprintf(temp
+ i
, "view %.*s", (int) (sizeof(temp
) - 7 - i
), fname
);
496 printw("%.*s", COLS
, temp
);
498 this_time
= time((time_t *) 0);
499 strcpy(temp
, ctime(&this_time
));
500 if ((i
= strlen(temp
)) != 0) {
502 if (move(0, COLS
- i
- 2) != ERR
)
506 scrollok(stdscr
, FALSE
); /* prevent screen from moving */
507 for (i
= 1; i
< LINES
; i
++) {
509 printw("%3ld:", (long) (lptr
+ i
- my_lines
));
511 if ((s
= lptr
[i
- 1]) != 0) {
516 add_wchstr(s
+ shift
);
524 setscrreg(1, LINES
- 1);
525 scrollok(stdscr
, TRUE
);