Revert "Ticket #3666: (size_trunc_len): fix segfault because of small buffer usage."
[midnight-commander.git] / src / viewer / display.c
blob40e57a64edd63569ef2788527726d8d9f4fe3468
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for whow info on display
5 Copyright (C) 1994-2016
6 Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Joseph M. Hinkle, 1996
13 Norbert Warmuth, 1997
14 Pavel Machek, 1998
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009
17 Andrew Borodin <aborodin@vmail.ru>, 2009, 2013
18 Ilia Maslakov <il.smind@gmail.com>, 2009, 2010
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software: you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation, either version 3 of the License,
25 or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program. If not, see <http://www.gnu.org/licenses/>.
36 #include <config.h>
37 #include <inttypes.h> /* uintmax_t */
39 #include "lib/global.h"
40 #include "lib/skin.h"
41 #include "lib/tty/tty.h"
42 #include "lib/tty/key.h"
43 #include "lib/strutil.h"
44 #include "lib/util.h"
45 #include "lib/widget.h"
46 #ifdef HAVE_CHARSET
47 #include "lib/charsets.h"
48 #endif
50 #include "src/setup.h" /* panels_options */
51 #include "src/keybind-defaults.h"
53 #include "internal.h"
55 /*** global variables ****************************************************************************/
57 /*** file scope macro definitions ****************************************************************/
59 #define BUF_TRUNC_LEN 5 /* The length of the line displays the file size */
61 /*** file scope type declarations ****************************************************************/
63 /*** file scope variables ************************************************************************/
65 /* If set, show a ruler */
66 static enum ruler_type
68 RULER_NONE,
69 RULER_TOP,
70 RULER_BOTTOM
71 } ruler = RULER_NONE;
73 /*** file scope functions ************************************************************************/
74 /* --------------------------------------------------------------------------------------------- */
76 /** Define labels and handlers for functional keys */
78 static void
79 mcview_set_buttonbar (WView * view)
81 WDialog *h = WIDGET (view)->owner;
82 WButtonBar *b = find_buttonbar (h);
83 const global_keymap_t *keymap = view->hex_mode ? viewer_hex_map : viewer_map;
85 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), keymap, WIDGET (view));
87 if (view->hex_mode)
89 if (view->hexedit_mode)
90 buttonbar_set_label (b, 2, Q_ ("ButtonBar|View"), keymap, WIDGET (view));
91 else if (view->datasource == DS_FILE)
92 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Edit"), keymap, WIDGET (view));
93 else
94 buttonbar_set_label (b, 2, "", keymap, WIDGET (view));
96 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Ascii"), keymap, WIDGET (view));
97 buttonbar_set_label (b, 6, Q_ ("ButtonBar|Save"), keymap, WIDGET (view));
98 buttonbar_set_label (b, 7, Q_ ("ButtonBar|HxSrch"), keymap, WIDGET (view));
101 else
103 buttonbar_set_label (b, 2, view->text_wrap_mode ? Q_ ("ButtonBar|UnWrap")
104 : Q_ ("ButtonBar|Wrap"), keymap, WIDGET (view));
105 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Hex"), keymap, WIDGET (view));
106 buttonbar_set_label (b, 6, "", keymap, WIDGET (view));
107 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), keymap, WIDGET (view));
110 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Goto"), keymap, WIDGET (view));
111 buttonbar_set_label (b, 8, view->magic_mode ? Q_ ("ButtonBar|Raw")
112 : Q_ ("ButtonBar|Parse"), keymap, WIDGET (view));
114 if (mcview_is_in_panel (view))
115 buttonbar_set_label (b, 10, "", keymap, WIDGET (view));
116 else
118 /* don't override some panel buttonbar keys */
119 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Quit"), keymap, WIDGET (view));
120 buttonbar_set_label (b, 9, view->text_nroff_mode ? Q_ ("ButtonBar|Unform")
121 : Q_ ("ButtonBar|Format"), keymap, WIDGET (view));
122 buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), keymap, WIDGET (view));
126 /* --------------------------------------------------------------------------------------------- */
128 static void
129 mcview_display_percent (WView * view, off_t p)
131 int percent;
133 percent = mcview_calc_percent (view, p);
134 if (percent >= 0)
136 const screen_dimen top = view->status_area.top;
137 const screen_dimen right = view->status_area.left + view->status_area.width;
139 widget_move (view, top, right - 4);
140 tty_printf ("%3d%%", percent);
141 /* avoid cursor wrapping in NCurses-base MC */
142 widget_move (view, top, right - 1);
146 /* --------------------------------------------------------------------------------------------- */
148 static void
149 mcview_display_status (WView * view)
151 const screen_dimen top = view->status_area.top;
152 const screen_dimen left = view->status_area.left;
153 const screen_dimen width = view->status_area.width;
154 const screen_dimen height = view->status_area.height;
155 const char *file_label;
157 if (height < 1)
158 return;
160 tty_setcolor (STATUSBAR_COLOR);
161 tty_draw_hline (WIDGET (view)->y + top, WIDGET (view)->x + left, ' ', width);
163 file_label =
164 view->filename_vpath != NULL ?
165 vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ?
166 view->command : "";
168 if (width > 40)
170 widget_move (view, top, width - 32);
171 if (view->hex_mode)
172 tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor);
173 else
175 char buffer[BUF_TRUNC_LEN + 1];
177 size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0,
178 panels_options.kilobyte_si);
179 tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end,
180 buffer, mcview_may_still_grow (view) ? "+" : " ",
181 #ifdef HAVE_CHARSET
182 mc_global.source_codepage >= 0 ?
183 get_codepage_id (mc_global.source_codepage) :
184 #endif
185 "");
188 widget_move (view, top, left);
189 if (width > 40)
190 tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT));
191 else
192 tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT));
193 if (width > 26)
194 mcview_display_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end);
197 /* --------------------------------------------------------------------------------------------- */
198 /*** public functions ****************************************************************************/
199 /* --------------------------------------------------------------------------------------------- */
201 void
202 mcview_update (WView * view)
204 static int dirt_limit = 1;
206 if (view->dpy_bbar_dirty)
208 view->dpy_bbar_dirty = FALSE;
209 mcview_set_buttonbar (view);
210 widget_redraw (WIDGET (find_buttonbar (WIDGET (view)->owner)));
213 if (view->dirty > dirt_limit)
215 /* Too many updates skipped -> force a update */
216 mcview_display (view);
217 view->dirty = 0;
218 /* Raise the update skipping limit */
219 dirt_limit++;
220 if (dirt_limit > mcview_max_dirt_limit)
221 dirt_limit = mcview_max_dirt_limit;
223 else if (view->dirty > 0)
225 if (is_idle ())
227 /* We have time to update the screen properly */
228 mcview_display (view);
229 view->dirty = 0;
230 if (dirt_limit > 1)
231 dirt_limit--;
233 else
235 /* We are busy -> skipping full update,
236 only the status line is updated */
237 mcview_display_status (view);
239 /* Here we had a refresh, if fast scrolling does not work
240 restore the refresh, although this should not happen */
244 /* --------------------------------------------------------------------------------------------- */
245 /** Displays as much data from view->dpy_start as fits on the screen */
247 void
248 mcview_display (WView * view)
250 if (view->hex_mode)
252 mcview_display_hex (view);
254 else
256 mcview_display_text (view);
258 mcview_display_status (view);
261 /* --------------------------------------------------------------------------------------------- */
263 void
264 mcview_compute_areas (WView * view)
266 struct area view_area;
267 screen_dimen height, rest, y;
269 /* The viewer is surrounded by a frame of size view->dpy_frame_size.
270 * Inside that frame, there are: The status line (at the top),
271 * the data area and an optional ruler, which is shown above or
272 * below the data area. */
274 view_area.top = view->dpy_frame_size;
275 view_area.left = view->dpy_frame_size;
276 view_area.height = mcview_dimen_doz (WIDGET (view)->lines, 2 * view->dpy_frame_size);
277 view_area.width = mcview_dimen_doz (WIDGET (view)->cols, 2 * view->dpy_frame_size);
279 /* Most coordinates of the areas equal those of the whole viewer */
280 view->status_area = view_area;
281 view->ruler_area = view_area;
282 view->data_area = view_area;
284 /* Compute the heights of the areas */
285 rest = view_area.height;
287 height = MIN (rest, 1);
288 view->status_area.height = height;
289 rest -= height;
291 height = (ruler == RULER_NONE || view->hex_mode) ? 0 : 2;
292 height = MIN (rest, height);
293 view->ruler_area.height = height;
294 rest -= height;
296 view->data_area.height = rest;
298 /* Compute the position of the areas */
299 y = view_area.top;
301 view->status_area.top = y;
302 y += view->status_area.height;
304 if (ruler == RULER_TOP)
306 view->ruler_area.top = y;
307 y += view->ruler_area.height;
310 view->data_area.top = y;
311 y += view->data_area.height;
313 if (ruler == RULER_BOTTOM)
314 view->ruler_area.top = y;
317 /* --------------------------------------------------------------------------------------------- */
319 void
320 mcview_update_bytes_per_line (WView * view)
322 const screen_dimen cols = view->data_area.width;
323 int bytes;
325 if (cols < 9 + 17)
326 bytes = 4;
327 else
328 bytes = 4 * ((cols - 9) / ((cols <= 80) ? 17 : 18));
329 #ifdef HAVE_ASSERT_H
330 assert (bytes != 0);
331 #endif
333 view->bytes_per_line = bytes;
334 view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */
337 /* --------------------------------------------------------------------------------------------- */
339 void
340 mcview_display_toggle_ruler (WView * view)
342 static const enum ruler_type next[3] =
344 RULER_TOP,
345 RULER_BOTTOM,
346 RULER_NONE
349 #ifdef HAVE_ASSERT_H
350 assert ((size_t) ruler < 3);
351 #endif
352 ruler = next[(size_t) ruler];
353 mcview_compute_areas (view);
354 view->dirty++;
357 /* --------------------------------------------------------------------------------------------- */
359 void
360 mcview_display_clean (WView * view)
362 Widget *w = WIDGET (view);
364 tty_setcolor (VIEW_NORMAL_COLOR);
365 widget_erase (w);
366 if (view->dpy_frame_size != 0)
367 tty_draw_box (w->y, w->x, w->lines, w->cols, FALSE);
370 /* --------------------------------------------------------------------------------------------- */
372 void
373 mcview_display_ruler (WView * view)
375 static const char ruler_chars[] = "|----*----";
376 const screen_dimen top = view->ruler_area.top;
377 const screen_dimen left = view->ruler_area.left;
378 const screen_dimen width = view->ruler_area.width;
379 const screen_dimen height = view->ruler_area.height;
380 const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
381 const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
383 char r_buff[10];
384 off_t cl;
385 screen_dimen c;
387 if (ruler == RULER_NONE || height < 1)
388 return;
390 tty_setcolor (VIEW_BOLD_COLOR);
391 for (c = 0; c < width; c++)
393 cl = view->dpy_text_column + c;
394 if (line_row < height)
396 widget_move (view, top + line_row, left + c);
397 tty_print_char (ruler_chars[cl % 10]);
400 if ((cl != 0) && (cl % 10) == 0)
402 g_snprintf (r_buff, sizeof (r_buff), "%" PRIuMAX, (uintmax_t) cl);
403 if (nums_row < height)
405 widget_move (view, top + nums_row, left + c - 1);
406 tty_print_string (r_buff);
410 tty_setcolor (VIEW_NORMAL_COLOR);
413 /* --------------------------------------------------------------------------------------------- */