Some little bugfixies for xz and lzma archives:
[midnight-commander.git] / src / viewer / mcviewer.c
blobc93d3bff3f3a115c56bbef663f8e6ea6e535ed4d
1 /*
2 Internal file viewer for the Midnight Commander
3 Interface functions
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009 Ilia Maslakov <il.smind@gmail.com>
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 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 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, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
38 #include <config.h>
39 #include <errno.h>
40 #include <fcntl.h>
42 #include "../src/global.h"
44 #include "../src/tty/tty.h"
46 #include "../src/strutil.h"
47 #include "../src/main.h"
48 #include "../src/charsets.h"
49 #include "../src/main-widgets.h" /* the_menubar */
50 #include "../src/menu.h" /* menubar_visible */
52 #include "internal.h"
53 #include "mcviewer.h"
55 /*** global variables ****************************************************************************/
57 int mcview_default_hex_mode = 0;
58 int mcview_default_nroff_flag = 0;
59 int mcview_global_wrap_mode = 1;
60 int mcview_default_magic_flag = 1;
62 int mcview_altered_hex_mode = 0;
63 int mcview_altered_magic_flag = 0;
64 int mcview_altered_nroff_flag = 0;
66 int mcview_remember_file_position = FALSE;
68 /* Maxlimit for skipping updates */
69 int mcview_max_dirt_limit = 10;
71 /* Scrolling is done in pages or line increments */
72 int mcview_mouse_move_pages = 1;
75 /*** file scope macro definitions ****************************************************************/
77 /*** file scope type declarations ****************************************************************/
79 /*** file scope variables ************************************************************************/
82 /*** file scope functions ************************************************************************/
84 /* --------------------------------------------------------------------------------------------- */
86 /* Both views */
87 static int
88 mcview_event (mcview_t *view, Gpm_Event *event, int *result)
90 screen_dimen y, x;
92 *result = MOU_NORMAL;
94 /* rest of the upper frame, the menu is invisible - call menu */
95 if (mcview_is_in_panel (view) && (event->type & GPM_DOWN)
96 && event->y == 1 && !menubar_visible) {
97 event->x += view->widget.x;
98 *result = the_menubar->widget.mouse (event, the_menubar);
99 return 0; /* don't draw viewer over menu */
102 /* We are not interested in the release events */
103 if (!(event->type & (GPM_DOWN | GPM_DRAG)))
104 return 0;
106 /* Wheel events */
107 if ((event->buttons & GPM_B_UP) && (event->type & GPM_DOWN)) {
108 mcview_move_up (view, 2);
109 return 1;
111 if ((event->buttons & GPM_B_DOWN) && (event->type & GPM_DOWN)) {
112 mcview_move_down (view, 2);
113 return 1;
116 x = event->x;
117 y = event->y;
119 /* Scrolling left and right */
120 if (!view->text_wrap_mode) {
121 if (x < view->data_area.width * 1 / 4) {
122 mcview_move_left (view, 1);
123 goto processed;
124 } else if (x < view->data_area.width * 3 / 4) {
125 /* ignore the click */
126 } else {
127 mcview_move_right (view, 1);
128 goto processed;
132 /* Scrolling up and down */
133 if (y < view->data_area.top + view->data_area.height * 1 / 3) {
134 if (mcview_mouse_move_pages)
135 mcview_move_up (view, view->data_area.height / 2);
136 else
137 mcview_move_up (view, 1);
138 goto processed;
139 } else if (y < view->data_area.top + view->data_area.height * 2 / 3) {
140 /* ignore the click */
141 } else {
142 if (mcview_mouse_move_pages)
143 mcview_move_down (view, view->data_area.height / 2);
144 else
145 mcview_move_down (view, 1);
146 goto processed;
149 return 0;
151 processed:
152 *result = MOU_REPEAT;
153 return 1;
156 /* --------------------------------------------------------------------------------------------- */
158 /* Real view only */
159 static int
160 mcview_real_event (Gpm_Event * event, void *x)
162 mcview_t *view = (mcview_t *) x;
163 int result;
165 if (mcview_event (view, event, &result))
166 mcview_update (view);
167 return result;
170 /* --------------------------------------------------------------------------------------------- */
172 /*** public functions ****************************************************************************/
174 /* --------------------------------------------------------------------------------------------- */
176 mcview_t *
177 mcview_new (int y, int x, int cols, int lines, int is_panel)
179 mcview_t *view = g_new0 (mcview_t, 1);
180 size_t i;
182 init_widget (&view->widget, y, x, lines, cols, mcview_callback, mcview_real_event);
184 view->filename = NULL;
185 view->command = NULL;
186 view->search_nroff_seq = NULL;
188 mcview_set_datasource_none (view);
190 view->growbuf_in_use = FALSE;
191 /* leave the other growbuf fields uninitialized */
193 view->hex_mode = FALSE;
194 view->hexedit_mode = FALSE;
195 view->hexview_in_text = FALSE;
196 view->text_nroff_mode = FALSE;
197 view->text_wrap_mode = FALSE;
198 view->magic_mode = FALSE;
199 view->utf8 = FALSE;
201 view->hexedit_lownibble = FALSE;
202 view->coord_cache = NULL;
204 view->dpy_frame_size = is_panel ? 1 : 0;
205 view->dpy_start = 0;
206 view->dpy_text_column = 0;
207 view->dpy_end = 0;
208 view->hex_cursor = 0;
209 view->cursor_col = 0;
210 view->cursor_row = 0;
211 view->change_list = NULL;
212 view->converter = str_cnv_from_term;
213 #ifdef HAVE_CHARSET
214 mcview_set_codeset (view);
215 #endif
216 /* {status,ruler,data}_area are left uninitialized */
218 view->dirty = 0;
219 view->dpy_bbar_dirty = TRUE;
220 view->bytes_per_line = 1;
222 view->search_start = 0;
223 view->search_end = 0;
225 view->want_to_quit = FALSE;
226 view->marker = 0;
227 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
228 view->marks[i] = 0;
230 view->move_dir = 0;
231 view->update_steps = 0;
232 view->update_activate = 0;
234 if (mcview_default_hex_mode)
235 mcview_toggle_hex_mode (view);
236 if (mcview_default_nroff_flag)
237 mcview_toggle_nroff_mode (view);
238 if (mcview_global_wrap_mode)
239 mcview_toggle_wrap_mode (view);
240 if (mcview_default_magic_flag)
241 mcview_toggle_magic_mode (view);
243 return view;
246 /* --------------------------------------------------------------------------------------------- */
248 /* Real view only */
250 mcview_viewer (const char *command, const char *file, int *move_dir_p, int start_line)
252 gboolean succeeded;
253 mcview_t *mcview_t;
254 WButtonBar *bar;
255 Dlg_head *view_dlg;
257 /* Create dialog and widgets, put them on the dialog */
258 view_dlg =
259 create_dlg (0, 0, LINES, COLS, NULL, mcview_dialog_callback,
260 "[Internal File Viewer]", NULL, DLG_WANT_TAB);
262 mcview_t = mcview_new (0, 0, COLS, LINES - 1, 0);
264 bar = buttonbar_new (1);
266 add_widget (view_dlg, bar);
267 add_widget (view_dlg, mcview_t);
269 succeeded = mcview_load (mcview_t, command, file, start_line);
270 if (succeeded) {
271 run_dlg (view_dlg);
272 if (move_dir_p)
273 *move_dir_p = mcview_t->move_dir;
274 } else {
275 if (move_dir_p)
276 *move_dir_p = 0;
278 destroy_dlg (view_dlg);
280 return succeeded;
283 /* {{{ Miscellaneous functions }}} */
285 /* --------------------------------------------------------------------------------------------- */
287 gboolean
288 mcview_load (mcview_t * view, const char *command, const char *file, int start_line)
290 int i, type;
291 int fd = -1;
292 char tmp[BUF_MEDIUM];
293 char *canon_fname;
294 struct stat st;
296 gboolean retval = FALSE;
298 assert (view->bytes_per_line != 0);
299 mcview_done (view);
301 /* Set up the state */
302 mcview_set_datasource_none (view);
303 view->filename = g_strdup (file);
304 view->command = 0;
306 /* Clear the markers */
307 view->marker = 0;
308 for (i = 0; i < 10; i++)
309 view->marks[i] = 0;
311 if (!mcview_is_in_panel (view)) {
312 view->dpy_text_column = 0;
315 if (command && (view->magic_mode || file == NULL || file[0] == '\0')) {
316 retval = mcview_load_command_output (view, command);
317 } else if (file != NULL && file[0] != '\0') {
318 /* Open the file */
319 if ((fd = mc_open (file, O_RDONLY | O_NONBLOCK)) == -1) {
320 g_snprintf (tmp, sizeof (tmp), _(" Cannot open \"%s\"\n %s "),
321 file, unix_error_string (errno));
322 mcview_show_error (view, tmp);
323 g_free (view->filename);
324 view->filename = NULL;
325 goto finish;
328 /* Make sure we are working with a regular file */
329 if (mc_fstat (fd, &st) == -1) {
330 mc_close (fd);
331 g_snprintf (tmp, sizeof (tmp), _(" Cannot stat \"%s\"\n %s "),
332 file, unix_error_string (errno));
333 mcview_show_error (view, tmp);
334 g_free (view->filename);
335 view->filename = NULL;
336 goto finish;
339 if (!S_ISREG (st.st_mode)) {
340 mc_close (fd);
341 mcview_show_error (view, _(" Cannot view: not a regular file "));
342 g_free (view->filename);
343 view->filename = NULL;
344 goto finish;
347 if (st.st_size == 0 || mc_lseek (fd, 0, SEEK_SET) == -1) {
348 /* Must be one of those nice files that grow (/proc) */
349 mcview_set_datasource_vfs_pipe (view, fd);
350 } else {
351 type = get_compression_type (fd, file);
353 if (view->magic_mode && (type != COMPRESSION_NONE)) {
354 g_free (view->filename);
355 view->filename = g_strconcat (file, decompress_extension (type), (char *) NULL);
357 mcview_set_datasource_file (view, fd, &st);
359 retval = TRUE;
362 finish:
363 view->command = g_strdup (command);
364 view->dpy_start = 0;
365 view->search_start = 0;
366 view->search_end = 0;
367 view->dpy_text_column = 0;
369 mcview_compute_areas (view);
370 assert (view->bytes_per_line != 0);
371 if (mcview_remember_file_position && view->filename != NULL && start_line == 0) {
372 long line, col;
374 canon_fname = vfs_canon (view->filename);
375 load_file_position (canon_fname, &line, &col);
376 g_free (canon_fname);
377 mcview_moveto (view, mcview_offset_doz (line, 1), col);
378 } else if (start_line > 0) {
379 mcview_moveto (view, start_line - 1, 0);
382 view->hexedit_lownibble = FALSE;
383 view->hexview_in_text = FALSE;
384 view->change_list = NULL;
385 return retval;
388 /* --------------------------------------------------------------------------------------------- */