422 строки
12 KiB
C
422 строки
12 KiB
C
/*
|
|
Internal file viewer for the Midnight Commander
|
|
Interface functions
|
|
|
|
Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
|
|
2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
|
|
|
|
Written by: 1994, 1995, 1998 Miguel de Icaza
|
|
1994, 1995 Janne Kukonlehto
|
|
1995 Jakub Jelinek
|
|
1996 Joseph M. Hinkle
|
|
1997 Norbert Warmuth
|
|
1998 Pavel Machek
|
|
2004 Roland Illig <roland.illig@gmx.de>
|
|
2005 Roland Illig <roland.illig@gmx.de>
|
|
2009 Slava Zanko <slavazanko@google.com>
|
|
2009 Andrew Borodin <aborodin@vmail.ru>
|
|
2009 Ilia Maslakov <il.smind@gmail.com>
|
|
|
|
This file is part of the Midnight Commander.
|
|
|
|
The Midnight Commander is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
The Midnight Commander is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "lib/global.h"
|
|
#include "lib/tty/tty.h"
|
|
#include "lib/tty/mouse.h"
|
|
#include "lib/vfs/mc-vfs/vfs.h"
|
|
#include "lib/strutil.h"
|
|
#include "lib/util.h" /* load_file_position() */
|
|
#include "lib/widget.h"
|
|
#include "lib/charsets.h"
|
|
|
|
#include "src/main.h"
|
|
|
|
#include "src/filemanager/layout.h" /* menubar_visible */
|
|
#include "src/filemanager/midnight.h" /* the_menubar */
|
|
|
|
#include "internal.h"
|
|
#include "mcviewer.h"
|
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
int mcview_default_hex_mode = 0;
|
|
int mcview_default_nroff_flag = 0;
|
|
int mcview_global_wrap_mode = 1;
|
|
int mcview_default_magic_flag = 1;
|
|
|
|
int mcview_altered_hex_mode = 0;
|
|
int mcview_altered_magic_flag = 0;
|
|
int mcview_altered_nroff_flag = 0;
|
|
|
|
int mcview_remember_file_position = FALSE;
|
|
|
|
/* Maxlimit for skipping updates */
|
|
int mcview_max_dirt_limit = 10;
|
|
|
|
/* Scrolling is done in pages or line increments */
|
|
int mcview_mouse_move_pages = 1;
|
|
|
|
/* end of file will be showen from mcview_show_eof */
|
|
char *mcview_show_eof = NULL;
|
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
/*** file scope variables ************************************************************************/
|
|
|
|
|
|
/*** file scope functions ************************************************************************/
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** Both views */
|
|
|
|
static int
|
|
mcview_event (mcview_t * view, Gpm_Event * event, int *result)
|
|
{
|
|
screen_dimen y, x;
|
|
|
|
*result = MOU_NORMAL;
|
|
|
|
/* rest of the upper frame, the menu is invisible - call menu */
|
|
if (mcview_is_in_panel (view) && (event->type & GPM_DOWN) && event->y == 1 && !menubar_visible)
|
|
{
|
|
event->x += view->widget.x;
|
|
*result = the_menubar->widget.mouse (event, the_menubar);
|
|
return 0; /* don't draw viewer over menu */
|
|
}
|
|
|
|
/* We are not interested in the release events */
|
|
if (!(event->type & (GPM_DOWN | GPM_DRAG)))
|
|
return 0;
|
|
|
|
/* Wheel events */
|
|
if ((event->buttons & GPM_B_UP) && (event->type & GPM_DOWN))
|
|
{
|
|
mcview_move_up (view, 2);
|
|
return 1;
|
|
}
|
|
if ((event->buttons & GPM_B_DOWN) && (event->type & GPM_DOWN))
|
|
{
|
|
mcview_move_down (view, 2);
|
|
return 1;
|
|
}
|
|
|
|
x = event->x;
|
|
y = event->y;
|
|
|
|
/* Scrolling left and right */
|
|
if (!view->text_wrap_mode)
|
|
{
|
|
if (x < view->data_area.width * 1 / 4)
|
|
{
|
|
mcview_move_left (view, 1);
|
|
goto processed;
|
|
}
|
|
else if (x < view->data_area.width * 3 / 4)
|
|
{
|
|
/* ignore the click */
|
|
}
|
|
else
|
|
{
|
|
mcview_move_right (view, 1);
|
|
goto processed;
|
|
}
|
|
}
|
|
|
|
/* Scrolling up and down */
|
|
if (y < view->data_area.top + view->data_area.height * 1 / 3)
|
|
{
|
|
if (mcview_mouse_move_pages)
|
|
mcview_move_up (view, view->data_area.height / 2);
|
|
else
|
|
mcview_move_up (view, 1);
|
|
goto processed;
|
|
}
|
|
else if (y < view->data_area.top + view->data_area.height * 2 / 3)
|
|
{
|
|
/* ignore the click */
|
|
}
|
|
else
|
|
{
|
|
if (mcview_mouse_move_pages)
|
|
mcview_move_down (view, view->data_area.height / 2);
|
|
else
|
|
mcview_move_down (view, 1);
|
|
goto processed;
|
|
}
|
|
|
|
return 0;
|
|
|
|
processed:
|
|
*result = MOU_REPEAT;
|
|
return 1;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
/** Real view only */
|
|
|
|
static int
|
|
mcview_real_event (Gpm_Event * event, void *x)
|
|
{
|
|
mcview_t *view = (mcview_t *) x;
|
|
int result;
|
|
|
|
if (mcview_event (view, event, &result))
|
|
mcview_update (view);
|
|
return result;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
static void
|
|
mcview_set_keymap (mcview_t * view)
|
|
{
|
|
view->plain_map = default_viewer_keymap;
|
|
if (viewer_keymap && viewer_keymap->len > 0)
|
|
view->plain_map = (global_keymap_t *) viewer_keymap->data;
|
|
|
|
view->hex_map = default_viewer_hex_keymap;
|
|
if (viewer_hex_keymap && viewer_hex_keymap->len > 0)
|
|
view->hex_map = (global_keymap_t *) viewer_hex_keymap->data;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
/*** public functions ****************************************************************************/
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
mcview_t *
|
|
mcview_new (int y, int x, int lines, int cols, gboolean is_panel)
|
|
{
|
|
mcview_t *view = g_new0 (mcview_t, 1);
|
|
|
|
init_widget (&view->widget, y, x, lines, cols, mcview_callback, mcview_real_event);
|
|
|
|
mcview_set_keymap (view);
|
|
|
|
view->hex_mode = FALSE;
|
|
view->hexedit_mode = FALSE;
|
|
view->locked = FALSE;
|
|
view->hexview_in_text = FALSE;
|
|
view->text_nroff_mode = FALSE;
|
|
view->text_wrap_mode = FALSE;
|
|
view->magic_mode = FALSE;
|
|
|
|
view->dpy_frame_size = is_panel ? 1 : 0;
|
|
view->converter = str_cnv_from_term;
|
|
|
|
mcview_init (view);
|
|
|
|
if (mcview_default_hex_mode)
|
|
mcview_toggle_hex_mode (view);
|
|
if (mcview_default_nroff_flag)
|
|
mcview_toggle_nroff_mode (view);
|
|
if (mcview_global_wrap_mode)
|
|
mcview_toggle_wrap_mode (view);
|
|
if (mcview_default_magic_flag)
|
|
mcview_toggle_magic_mode (view);
|
|
|
|
return view;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
/** Real view only */
|
|
|
|
mcview_ret_t
|
|
mcview_viewer (const char *command, const char *file, int start_line)
|
|
{
|
|
gboolean succeeded;
|
|
mcview_t *lc_mcview;
|
|
Dlg_head *view_dlg;
|
|
mcview_ret_t ret;
|
|
|
|
/* Create dialog and widgets, put them on the dialog */
|
|
view_dlg = create_dlg (FALSE, 0, 0, LINES, COLS, NULL, mcview_dialog_callback,
|
|
"[Internal File Viewer]", NULL, DLG_WANT_TAB);
|
|
|
|
lc_mcview = mcview_new (0, 0, LINES - 1, COLS, FALSE);
|
|
add_widget (view_dlg, lc_mcview);
|
|
|
|
add_widget (view_dlg, buttonbar_new (TRUE));
|
|
|
|
view_dlg->get_title = mcview_get_title;
|
|
|
|
succeeded = mcview_load (lc_mcview, command, file, start_line);
|
|
|
|
if (succeeded)
|
|
{
|
|
run_dlg (view_dlg);
|
|
|
|
ret = lc_mcview->move_dir == 0 ? MCVIEW_EXIT_OK :
|
|
lc_mcview->move_dir > 0 ? MCVIEW_WANT_NEXT : MCVIEW_WANT_PREV;
|
|
}
|
|
else
|
|
{
|
|
view_dlg->state = DLG_CLOSED;
|
|
ret = MCVIEW_EXIT_FAILURE;
|
|
}
|
|
|
|
if (view_dlg->state == DLG_CLOSED)
|
|
destroy_dlg (view_dlg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* {{{ Miscellaneous functions }}} */
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
gboolean
|
|
mcview_load (mcview_t * view, const char *command, const char *file, int start_line)
|
|
{
|
|
gboolean retval = FALSE;
|
|
|
|
assert (view->bytes_per_line != 0);
|
|
|
|
view->filename = g_strdup (file);
|
|
|
|
if ((view->workdir == NULL) && (file != NULL))
|
|
{
|
|
if (!g_path_is_absolute (file))
|
|
view->workdir = g_strdup (vfs_get_current_dir ());
|
|
else
|
|
{
|
|
/* try extract path form filename */
|
|
char *dirname;
|
|
|
|
dirname = g_path_get_dirname (file);
|
|
if (strcmp (dirname, ".") != 0)
|
|
view->workdir = dirname;
|
|
else
|
|
{
|
|
g_free (dirname);
|
|
view->workdir = g_strdup (vfs_get_current_dir ());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!mcview_is_in_panel (view))
|
|
view->dpy_text_column = 0;
|
|
|
|
mcview_set_codeset (view);
|
|
|
|
if (command != NULL && (view->magic_mode || file == NULL || file[0] == '\0'))
|
|
retval = mcview_load_command_output (view, command);
|
|
else if (file != NULL && file[0] != '\0')
|
|
{
|
|
int fd = -1;
|
|
char tmp[BUF_MEDIUM];
|
|
struct stat st;
|
|
|
|
/* Open the file */
|
|
fd = mc_open (file, O_RDONLY | O_NONBLOCK);
|
|
if (fd == -1)
|
|
{
|
|
g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\"\n%s"),
|
|
file, unix_error_string (errno));
|
|
mcview_show_error (view, tmp);
|
|
g_free (view->filename);
|
|
view->filename = NULL;
|
|
g_free (view->workdir);
|
|
view->workdir = NULL;
|
|
goto finish;
|
|
}
|
|
|
|
/* Make sure we are working with a regular file */
|
|
if (mc_fstat (fd, &st) == -1)
|
|
{
|
|
mc_close (fd);
|
|
g_snprintf (tmp, sizeof (tmp), _("Cannot stat \"%s\"\n%s"),
|
|
file, unix_error_string (errno));
|
|
mcview_show_error (view, tmp);
|
|
g_free (view->filename);
|
|
view->filename = NULL;
|
|
g_free (view->workdir);
|
|
view->workdir = NULL;
|
|
goto finish;
|
|
}
|
|
|
|
if (!S_ISREG (st.st_mode))
|
|
{
|
|
mc_close (fd);
|
|
mcview_show_error (view, _("Cannot view: not a regular file"));
|
|
g_free (view->filename);
|
|
view->filename = NULL;
|
|
g_free (view->workdir);
|
|
view->workdir = NULL;
|
|
goto finish;
|
|
}
|
|
|
|
if (st.st_size == 0 || mc_lseek (fd, 0, SEEK_SET) == -1)
|
|
{
|
|
/* Must be one of those nice files that grow (/proc) */
|
|
mcview_set_datasource_vfs_pipe (view, fd);
|
|
}
|
|
else
|
|
{
|
|
int type;
|
|
|
|
type = get_compression_type (fd, file);
|
|
|
|
if (view->magic_mode && (type != COMPRESSION_NONE))
|
|
{
|
|
g_free (view->filename);
|
|
view->filename = g_strconcat (file, decompress_extension (type), (char *) NULL);
|
|
}
|
|
mcview_set_datasource_file (view, fd, &st);
|
|
}
|
|
retval = TRUE;
|
|
}
|
|
|
|
finish:
|
|
view->command = g_strdup (command);
|
|
view->dpy_start = 0;
|
|
view->search_start = 0;
|
|
view->search_end = 0;
|
|
view->dpy_text_column = 0;
|
|
|
|
mcview_compute_areas (view);
|
|
mcview_update_bytes_per_line (view);
|
|
|
|
if (mcview_remember_file_position && view->filename != NULL && start_line == 0)
|
|
{
|
|
char *canon_fname;
|
|
long line, col;
|
|
off_t new_offset;
|
|
|
|
canon_fname = vfs_canon (view->filename);
|
|
load_file_position (canon_fname, &line, &col, &new_offset, &view->saved_bookmarks);
|
|
new_offset = min (new_offset, mcview_get_filesize (view));
|
|
view->dpy_start = mcview_bol (view, new_offset, 0);
|
|
g_free (canon_fname);
|
|
}
|
|
else if (start_line > 0)
|
|
mcview_moveto (view, start_line - 1, 0);
|
|
|
|
view->hexedit_lownibble = FALSE;
|
|
view->hexview_in_text = FALSE;
|
|
view->change_list = NULL;
|
|
return retval;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|