2 Internal file viewer for the Midnight Commander
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
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,
42 #include "lib/global.h"
43 #include "lib/tty/tty.h"
44 #include "lib/vfs/mc-vfs/vfs.h"
45 #include "lib/strutil.h"
48 #include "src/charsets.h"
49 #include "src/main-widgets.h" /* the_menubar */
50 #include "src/menu.h" /* menubar_visible */
51 #include "src/widget.h"
56 /*** global variables ****************************************************************************/
58 int mcview_default_hex_mode
= 0;
59 int mcview_default_nroff_flag
= 0;
60 int mcview_global_wrap_mode
= 1;
61 int mcview_default_magic_flag
= 1;
63 int mcview_altered_hex_mode
= 0;
64 int mcview_altered_magic_flag
= 0;
65 int mcview_altered_nroff_flag
= 0;
67 int mcview_remember_file_position
= FALSE
;
69 /* Maxlimit for skipping updates */
70 int mcview_max_dirt_limit
= 10;
72 /* Scrolling is done in pages or line increments */
73 int mcview_mouse_move_pages
= 1;
75 /* end of file will be showen from mcview_show_eof */
76 char *mcview_show_eof
= NULL
;
78 /*** file scope macro definitions ****************************************************************/
80 /*** file scope type declarations ****************************************************************/
82 /*** file scope variables ************************************************************************/
85 /*** file scope functions ************************************************************************/
87 /* --------------------------------------------------------------------------------------------- */
91 mcview_event (mcview_t
* view
, Gpm_Event
* event
, int *result
)
97 /* rest of the upper frame, the menu is invisible - call menu */
98 if (mcview_is_in_panel (view
) && (event
->type
& GPM_DOWN
) && event
->y
== 1 && !menubar_visible
)
100 event
->x
+= view
->widget
.x
;
101 *result
= the_menubar
->widget
.mouse (event
, the_menubar
);
102 return 0; /* don't draw viewer over menu */
105 /* We are not interested in the release events */
106 if (!(event
->type
& (GPM_DOWN
| GPM_DRAG
)))
110 if ((event
->buttons
& GPM_B_UP
) && (event
->type
& GPM_DOWN
))
112 mcview_move_up (view
, 2);
115 if ((event
->buttons
& GPM_B_DOWN
) && (event
->type
& GPM_DOWN
))
117 mcview_move_down (view
, 2);
124 /* Scrolling left and right */
125 if (!view
->text_wrap_mode
)
127 if (x
< view
->data_area
.width
* 1 / 4)
129 mcview_move_left (view
, 1);
132 else if (x
< view
->data_area
.width
* 3 / 4)
134 /* ignore the click */
138 mcview_move_right (view
, 1);
143 /* Scrolling up and down */
144 if (y
< view
->data_area
.top
+ view
->data_area
.height
* 1 / 3)
146 if (mcview_mouse_move_pages
)
147 mcview_move_up (view
, view
->data_area
.height
/ 2);
149 mcview_move_up (view
, 1);
152 else if (y
< view
->data_area
.top
+ view
->data_area
.height
* 2 / 3)
154 /* ignore the click */
158 if (mcview_mouse_move_pages
)
159 mcview_move_down (view
, view
->data_area
.height
/ 2);
161 mcview_move_down (view
, 1);
168 *result
= MOU_REPEAT
;
172 /* --------------------------------------------------------------------------------------------- */
176 mcview_real_event (Gpm_Event
* event
, void *x
)
178 mcview_t
*view
= (mcview_t
*) x
;
181 if (mcview_event (view
, event
, &result
))
182 mcview_update (view
);
187 mcview_set_keymap (mcview_t
* view
)
189 view
->plain_map
= default_viewer_keymap
;
190 if (viewer_keymap
&& viewer_keymap
->len
> 0)
191 view
->plain_map
= (global_keymap_t
*) viewer_keymap
->data
;
193 view
->hex_map
= default_viewer_hex_keymap
;
194 if (viewer_hex_keymap
&& viewer_hex_keymap
->len
> 0)
195 view
->hex_map
= (global_keymap_t
*) viewer_hex_keymap
->data
;
198 /* --------------------------------------------------------------------------------------------- */
200 /*** public functions ****************************************************************************/
202 /* --------------------------------------------------------------------------------------------- */
205 mcview_new (int y
, int x
, int lines
, int cols
, int is_panel
)
207 mcview_t
*view
= g_new0 (mcview_t
, 1);
210 init_widget (&view
->widget
, y
, x
, lines
, cols
, mcview_callback
, mcview_real_event
);
212 view
->filename
= NULL
;
213 view
->command
= NULL
;
214 view
->search_nroff_seq
= NULL
;
216 mcview_set_datasource_none (view
);
218 view
->growbuf_in_use
= FALSE
;
219 /* leave the other growbuf fields uninitialized */
221 view
->hex_mode
= FALSE
;
222 view
->hexedit_mode
= FALSE
;
223 view
->hexview_in_text
= FALSE
;
224 view
->text_nroff_mode
= FALSE
;
225 view
->text_wrap_mode
= FALSE
;
226 view
->magic_mode
= FALSE
;
229 view
->hexedit_lownibble
= FALSE
;
230 view
->coord_cache
= NULL
;
232 view
->dpy_frame_size
= is_panel
? 1 : 0;
234 view
->dpy_text_column
= 0;
236 view
->hex_cursor
= 0;
237 view
->cursor_col
= 0;
238 view
->cursor_row
= 0;
239 view
->change_list
= NULL
;
240 view
->converter
= str_cnv_from_term
;
241 mcview_set_codeset (view
);
242 /* {status,ruler,data}_area are left uninitialized */
245 view
->dpy_bbar_dirty
= TRUE
;
246 view
->bytes_per_line
= 1;
248 view
->search_start
= 0;
249 view
->search_end
= 0;
251 view
->want_to_quit
= FALSE
;
253 for (i
= 0; i
< sizeof (view
->marks
) / sizeof (view
->marks
[0]); i
++)
257 view
->update_steps
= 0;
258 view
->update_activate
= 0;
260 if (mcview_default_hex_mode
)
261 mcview_toggle_hex_mode (view
);
262 if (mcview_default_nroff_flag
)
263 mcview_toggle_nroff_mode (view
);
264 if (mcview_global_wrap_mode
)
265 mcview_toggle_wrap_mode (view
);
266 if (mcview_default_magic_flag
)
267 mcview_toggle_magic_mode (view
);
269 mcview_set_keymap (view
);
274 /* --------------------------------------------------------------------------------------------- */
278 mcview_viewer (const char *command
, const char *file
, int *move_dir_p
, int start_line
)
284 /* Create dialog and widgets, put them on the dialog */
285 view_dlg
= create_dlg (0, 0, LINES
, COLS
, NULL
, mcview_dialog_callback
,
286 "[Internal File Viewer]", NULL
, DLG_WANT_TAB
);
288 lc_mcview
= mcview_new (0, 0, LINES
- 1, COLS
, 0);
289 add_widget (view_dlg
, lc_mcview
);
291 add_widget (view_dlg
, buttonbar_new (TRUE
));
293 succeeded
= mcview_load (lc_mcview
, command
, file
, start_line
);
298 *move_dir_p
= lc_mcview
->move_dir
;
305 destroy_dlg (view_dlg
);
310 /* {{{ Miscellaneous functions }}} */
312 /* --------------------------------------------------------------------------------------------- */
315 mcview_load (mcview_t
* view
, const char *command
, const char *file
, int start_line
)
319 char tmp
[BUF_MEDIUM
];
323 gboolean retval
= FALSE
;
325 assert (view
->bytes_per_line
!= 0);
328 /* Set up the state */
329 mcview_set_datasource_none (view
);
330 view
->filename
= g_strdup (file
);
333 /* Clear the markers */
335 for (i
= 0; i
< 10; i
++)
338 if (!mcview_is_in_panel (view
))
340 view
->dpy_text_column
= 0;
343 if (command
&& (view
->magic_mode
|| file
== NULL
|| file
[0] == '\0'))
345 retval
= mcview_load_command_output (view
, command
);
347 else if (file
!= NULL
&& file
[0] != '\0')
350 if ((fd
= mc_open (file
, O_RDONLY
| O_NONBLOCK
)) == -1)
352 g_snprintf (tmp
, sizeof (tmp
), _(" Cannot open \"%s\"\n %s "),
353 file
, unix_error_string (errno
));
354 mcview_show_error (view
, tmp
);
355 g_free (view
->filename
);
356 view
->filename
= NULL
;
360 /* Make sure we are working with a regular file */
361 if (mc_fstat (fd
, &st
) == -1)
364 g_snprintf (tmp
, sizeof (tmp
), _(" Cannot stat \"%s\"\n %s "),
365 file
, unix_error_string (errno
));
366 mcview_show_error (view
, tmp
);
367 g_free (view
->filename
);
368 view
->filename
= NULL
;
372 if (!S_ISREG (st
.st_mode
))
375 mcview_show_error (view
, _(" Cannot view: not a regular file "));
376 g_free (view
->filename
);
377 view
->filename
= NULL
;
381 if (st
.st_size
== 0 || mc_lseek (fd
, 0, SEEK_SET
) == -1)
383 /* Must be one of those nice files that grow (/proc) */
384 mcview_set_datasource_vfs_pipe (view
, fd
);
388 type
= get_compression_type (fd
, file
);
390 if (view
->magic_mode
&& (type
!= COMPRESSION_NONE
))
392 g_free (view
->filename
);
393 view
->filename
= g_strconcat (file
, decompress_extension (type
), (char *) NULL
);
395 mcview_set_datasource_file (view
, fd
, &st
);
401 view
->command
= g_strdup (command
);
403 view
->search_start
= 0;
404 view
->search_end
= 0;
405 view
->dpy_text_column
= 0;
407 mcview_compute_areas (view
);
408 mcview_update_bytes_per_line (view
);
410 if (mcview_remember_file_position
&& view
->filename
!= NULL
&& start_line
== 0)
414 canon_fname
= vfs_canon (view
->filename
);
415 load_file_position (canon_fname
, &line
, &col
, &new_offset
);
416 new_offset
= min (new_offset
, mcview_get_filesize (view
));
417 view
->dpy_start
= mcview_bol (view
, new_offset
);
418 g_free (canon_fname
);
420 else if (start_line
> 0)
422 mcview_moveto (view
, start_line
- 1, 0);
425 view
->hexedit_lownibble
= FALSE
;
426 view
->hexview_in_text
= FALSE
;
427 view
->change_list
= NULL
;
431 /* --------------------------------------------------------------------------------------------- */