2 * $Id: tailbox.c,v 1.68 2012/11/18 15:48:52 tom Exp $
4 * tailbox.c -- implements the tail box
6 * Copyright 2000-2011,2012 Thomas E. Dickey
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License, version 2.1
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to
19 * Free Software Foundation, Inc.
20 * 51 Franklin St., Fifth Floor
21 * Boston, MA 02110, USA.
23 * An earlier version of this program lists as authors
24 * Pasquale De Marco (demarco_p@abramo.it)
37 char line
[MAX_LEN
+ 2];
42 * Return current line of text.
45 get_line(MY_OBJ
* obj
)
47 FILE *fp
= obj
->obj
.input
;
48 int col
= -(obj
->hscroll
);
52 if (((ch
= getc(fp
)) == EOF
) && !feof(fp
))
53 dlg_exiterr("Error moving file pointer in get_line().");
54 else if (!feof(fp
) && (ch
!= '\n')) {
55 if ((ch
== TAB
) && (dialog_vars
.tab_correct
)) {
56 tmpint
= dialog_state
.tab_len
57 - ((col
+ obj
->hscroll
) % dialog_state
.tab_len
);
58 for (j
= 0; j
< tmpint
; j
++) {
59 if (col
>= 0 && col
< MAX_LEN
)
65 obj
->line
[col
] = (char) ch
;
71 } while (!feof(fp
) && (ch
!= '\n'));
75 obj
->line
[col
] = '\0';
81 * Print a new line of text.
84 print_line(MY_OBJ
* obj
, WINDOW
*win
, int row
, int width
)
87 char *line
= get_line(obj
);
89 (void) wmove(win
, row
, 0); /* move cursor to correct line */
90 (void) waddch(win
, ' ');
91 #ifdef NCURSES_VERSION
92 (void) waddnstr(win
, line
, MIN((int) strlen(line
), width
- 2));
94 line
[MIN((int) strlen(line
), width
- 2)] = '\0';
100 /* Clear 'residue' of previous line */
101 for (i
= 0; i
< width
- x
; i
++)
102 (void) waddch(win
, ' ');
106 * Go back 'target' lines in text file. BUFSIZ has to be in 'size_t' range.
109 last_lines(MY_OBJ
* obj
, int target
)
111 FILE *fp
= obj
->obj
.input
;
114 char buf
[BUFSIZ
+ 1];
120 if (fseek(fp
, 0L, SEEK_END
) == -1
121 || (fpos
= ftell(fp
)) < 0)
122 dlg_exiterr("Error moving file pointer in last_lines().");
127 if (fpos
>= BUFSIZ
) {
128 size_to_read
= BUFSIZ
;
130 size_to_read
= (size_t) fpos
;
132 fpos
= fpos
- (long) size_to_read
;
133 if (fseek(fp
, fpos
, SEEK_SET
) == -1)
134 dlg_exiterr("Error moving file pointer in last_lines().");
135 size_as_read
= fread(buf
, sizeof(char), size_to_read
, fp
);
137 dlg_exiterr("Error reading file in last_lines().");
139 if (size_as_read
== 0) {
145 offset
+= (long) size_as_read
;
146 for (inx
= size_as_read
- 1; inx
!= 0; --inx
) {
147 if (buf
[inx
] == '\n') {
148 if (++count
> target
)
150 offset
= (long) (inx
+ 1);
154 if (count
> target
) {
156 } else if (fpos
== 0) {
162 if (fseek(fp
, fpos
+ offset
, SEEK_SET
) == -1)
163 dlg_exiterr("Error moving file pointer in last_lines().");
168 * Print a new page of text.
171 print_page(MY_OBJ
* obj
, int height
, int width
)
175 for (i
= 0; i
< height
; i
++) {
176 print_line(obj
, obj
->text
, i
, width
);
178 (void) wnoutrefresh(obj
->text
);
182 print_last_page(MY_OBJ
* obj
)
184 int high
= getmaxy(obj
->obj
.win
) - (2 * MARGIN
+ (obj
->obj
.bg_task
? 1 : 3));
185 int wide
= getmaxx(obj
->text
);
187 last_lines(obj
, high
);
188 print_page(obj
, high
, wide
);
192 repaint_text(MY_OBJ
* obj
)
194 FILE *fp
= obj
->obj
.input
;
197 getyx(obj
->obj
.win
, cur_y
, cur_x
);
198 obj
->old_hscroll
= obj
->hscroll
;
200 print_last_page(obj
);
201 obj
->last_pos
= ftell(fp
);
203 (void) wmove(obj
->obj
.win
, cur_y
, cur_x
); /* Restore cursor position */
204 wrefresh(obj
->obj
.win
);
208 handle_input(DIALOG_CALLBACK
* cb
)
210 MY_OBJ
*obj
= (MY_OBJ
*) cb
;
211 FILE *fp
= obj
->obj
.input
;
214 if (fstat(fileno(fp
), &sb
) == 0
215 && sb
.st_size
!= obj
->last_pos
) {
223 handle_my_getc(DIALOG_CALLBACK
* cb
, int ch
, int fkey
, int *result
)
225 MY_OBJ
*obj
= (MY_OBJ
*) cb
;
228 if (!fkey
&& dlg_char_to_button(ch
, obj
->buttons
) == 0) {
236 *result
= DLG_EXIT_OK
;
239 case DLGK_BEGIN
: /* Beginning of line */
242 case DLGK_GRID_LEFT
: /* Scroll left */
243 if (obj
->hscroll
> 0) {
247 case DLGK_GRID_RIGHT
: /* Scroll right */
248 if (obj
->hscroll
< MAX_LEN
)
255 if ((obj
->hscroll
!= obj
->old_hscroll
))
261 ch
= getc(cb
->input
);
262 (void) ungetc(ch
, cb
->input
);
269 *result
= DLG_EXIT_ESC
;
281 * Display text from a file in a dialog box, like in a "tail -f".
284 dialog_tailbox(const char *title
, const char *file
, int height
, int width
, int bg_task
)
287 static DLG_KEYS_BINDING binding
[] = {
290 DLG_KEYS_DATA( DLGK_BEGIN
, '0' ),
291 DLG_KEYS_DATA( DLGK_BEGIN
, KEY_BEG
),
292 DLG_KEYS_DATA( DLGK_GRID_LEFT
, 'H' ),
293 DLG_KEYS_DATA( DLGK_GRID_LEFT
, 'h' ),
294 DLG_KEYS_DATA( DLGK_GRID_LEFT
, KEY_LEFT
),
295 DLG_KEYS_DATA( DLGK_GRID_RIGHT
, 'L' ),
296 DLG_KEYS_DATA( DLGK_GRID_RIGHT
, 'l' ),
297 DLG_KEYS_DATA( DLGK_GRID_RIGHT
, KEY_RIGHT
),
303 int old_height
= height
;
304 int old_width
= width
;
307 int x
, y
, result
, thigh
;
308 WINDOW
*dialog
, *text
;
309 const char **buttons
= 0;
314 /* Open input file for reading */
315 if ((fd
= fopen(file
, "rb")) == NULL
)
316 dlg_exiterr("Can't open input file in dialog_tailbox().");
321 dlg_auto_sizefile(title
, file
, &height
, &width
, 2, min_width
);
322 dlg_print_size(height
, width
);
323 dlg_ctl_size(height
, width
);
325 x
= dlg_box_x_ordinate(width
);
326 y
= dlg_box_y_ordinate(height
);
327 thigh
= height
- ((2 * MARGIN
) + (bg_task
? 0 : 2));
329 dialog
= dlg_new_window(height
, width
, y
, x
);
331 dlg_mouse_setbase(x
, y
);
333 /* Create window for text region, used for scrolling text */
334 text
= dlg_sub_window(dialog
,
336 width
- (2 * MARGIN
),
340 dlg_draw_box2(dialog
, 0, 0, height
, width
, dialog_attr
, border_attr
, border2_attr
);
341 dlg_draw_bottom_box2(dialog
, border_attr
, border2_attr
, dialog_attr
);
342 dlg_draw_title(dialog
, title
);
343 dlg_draw_helpline(dialog
, FALSE
);
346 buttons
= dlg_exit_label();
347 dlg_button_layout(buttons
, &min_width
);
348 dlg_draw_buttons(dialog
, height
- (2 * MARGIN
), 0, buttons
, FALSE
,
352 (void) wmove(dialog
, thigh
, (MARGIN
+ 1));
353 (void) wnoutrefresh(dialog
);
355 obj
= dlg_calloc(MY_OBJ
, 1);
356 assert_ptr(obj
, "dialog_tailbox");
359 obj
->obj
.win
= dialog
;
360 obj
->obj
.handle_getc
= handle_my_getc
;
361 obj
->obj
.handle_input
= bg_task
? handle_input
: 0;
362 obj
->obj
.keep_bg
= bg_task
&& dialog_vars
.cant_kill
;
363 obj
->obj
.bg_task
= bg_task
;
365 obj
->buttons
= buttons
;
366 dlg_add_callback(&(obj
->obj
));
368 dlg_register_window(dialog
, "tailbox", binding
);
369 dlg_register_buttons(dialog
, "tailbox", buttons
);
371 /* Print last page of text */
372 dlg_attr_clear(text
, thigh
, getmaxx(text
), dialog_attr
);
375 dlg_trace_win(dialog
);
377 result
= DLG_EXIT_OK
;
381 ch
= dlg_getc(dialog
, &fkey
);
383 if (fkey
&& ch
== KEY_RESIZE
) {
389 dlg_del_window(dialog
);
391 dlg_mouse_free_regions();
392 dlg_button_layout(buttons
, &min_width
);
397 while (handle_my_getc(&(obj
->obj
), ch
, fkey
, &result
));
399 dlg_mouse_free_regions();