Merge branch 'DEV_mcview2'

* DEV_mcview2: (27 commits)
  Implemented interruptable long-distance movements.
  fix: <no translation> behaviour
  Change prototype of mcview_get_byte() function (and al related functions)
  fix: uninitialized variables
  fix: header paths
  Added missed includes. Fixed OFFSETTYPE_MAX calculation.
  Cleanup of code. Indentation.
  Ticket #1530
  * add 'Whole words' option into the viewer 'Search' dialog
  Added functions for work with nroff'ed text. Added search across nroff'ed text
  Fixies with search in HEX mode view:
  Search in plain text (not nroff'ed) now worked.
  Cleanup of code. Reidentation.
  Ticket #1431 (Missing translation in view.c ButtonBar?)
  Avoid warning 'format not a string literal and no format arguments'.
  Fixed memory leak after geting list of search types.
  Move search dialog from actions_cmd.c into dialogs.c
  Changes for correctly work after rebase to master (master with HACK_tty).
  fix: draw nroff text
  Move inline functions from internal.h into new file inlines.h
  ...
This commit is contained in:
Slava Zanko 2009-08-25 11:52:23 +03:00
commit 5257a79847
28 changed files with 4964 additions and 4082 deletions

View File

@ -562,6 +562,7 @@ src/Makefile
src/mcconfig/Makefile
src/search/Makefile
src/tty/Makefile
src/viewer/Makefile
edit/Makefile
syntax/Makefile

View File

@ -111,7 +111,7 @@ editcmd_dialog_replace_show (WEdit * edit, const char *search_default, const cha
&tall_codepages, 0, NULL, NULL, NULL},
#endif
{quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("Whole &words"), 0, 0,
{quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Whole words"), 0, 0,
&twhole_words, 0, NULL, NULL, NULL},
@ -206,7 +206,7 @@ editcmd_dialog_search_show (WEdit * edit, char **search_text)
&tall_codepages, 0, NULL, NULL, NULL},
#endif
{quick_checkbox, 33, SEARCH_DLG_WIDTH, 8, SEARCH_DLG_HEIGHT, N_("Whole &words"), 0, 0,
{quick_checkbox, 33, SEARCH_DLG_WIDTH, 8, SEARCH_DLG_HEIGHT, N_("&Whole words"), 0, 0,
&twhole_words, 0, NULL, NULL, NULL},
{quick_checkbox, 33, SEARCH_DLG_WIDTH, 7, SEARCH_DLG_HEIGHT, N_("In se&lection"), 0, 0,

View File

@ -1,4 +1,4 @@
SUBDIRS = mcconfig search tty
SUBDIRS = mcconfig search tty viewer
AM_CFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) $(PCRE_CFLAGS)
@ -42,9 +42,10 @@ endif
MCCONFIGLIB = mcconfig/libmcconfig.la
SEARCHLIB = search/libsearch.la
TTYLIB = tty/libmctty.la
VIEWERLIB = viewer/libmcviewer.la
mc_LDADD = $(EDITLIB) $(VFSLIB) \
$(MCCONFIGLIB) $(SEARCHLIB) $(TTYLIB) \
$(MCCONFIGLIB) $(SEARCHLIB) $(TTYLIB) $(VIEWERLIB) \
$(INTLLIBS) $(MCLIBS) $(SLANGLIB) $(LIBICONV) $(GLIB_LIBS)
CHARSET_SRC = charsets.c charsets.h selcodepage.c selcodepage.h
@ -66,7 +67,7 @@ SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \
screen.c setup.c setup.h \
subshell.c subshell.h textconf.c textconf.h \
tree.c tree.h treestore.c treestore.h timefmt.h user.c \
user.h util.c util.h utilunix.c view.c view.h vfsdummy.h \
user.h util.c util.h utilunix.c vfsdummy.h \
widget.c widget.h wtools.c wtools.h unixcompat.h \
ecs.h ecs.c \
strutil.h strutil.c strutilascii.c strutil8bit.c strutilutf8.c \

View File

@ -64,7 +64,6 @@
#include "subshell.h" /* use_subshell */
#include "cons.saver.h" /* console_flag */
#include "dialog.h" /* Widget */
#include "view.h" /* mc_internal_viewer() */
#include "wtools.h" /* message() */
#include "widget.h" /* push_history() */
#include "main.h" /* change_panel() */
@ -80,6 +79,7 @@
#include "history.h"
#include "strutil.h"
#include "dir.h"
#include "../src/viewer/mcviewer.h"
#ifndef MAP_FILE
# define MAP_FILE 0
@ -123,25 +123,25 @@ view_file_at_line (const char *filename, int plain_view, int internal,
int changed_nroff_flag = 0;
int changed_magic_flag = 0;
altered_hex_mode = 0;
altered_nroff_flag = 0;
altered_magic_flag = 0;
if (default_hex_mode)
mcview_altered_hex_mode = 0;
mcview_altered_nroff_flag = 0;
mcview_altered_magic_flag = 0;
if (mcview_default_hex_mode)
changed_hex_mode = 1;
if (default_nroff_flag)
if (mcview_default_nroff_flag)
changed_nroff_flag = 1;
if (default_magic_flag)
if (mcview_default_magic_flag)
changed_magic_flag = 1;
default_hex_mode = 0;
default_nroff_flag = 0;
default_magic_flag = 0;
mc_internal_viewer (NULL, filename, &move_dir, start_line);
if (changed_hex_mode && !altered_hex_mode)
default_hex_mode = 1;
if (changed_nroff_flag && !altered_nroff_flag)
default_nroff_flag = 1;
if (changed_magic_flag && !altered_magic_flag)
default_magic_flag = 1;
mcview_default_hex_mode = 0;
mcview_default_nroff_flag = 0;
mcview_default_magic_flag = 0;
mcview_viewer (NULL, filename, &move_dir, start_line);
if (changed_hex_mode && !mcview_altered_hex_mode)
mcview_default_hex_mode = 1;
if (changed_nroff_flag && !mcview_altered_nroff_flag)
mcview_default_nroff_flag = 1;
if (changed_magic_flag && !mcview_altered_magic_flag)
mcview_default_magic_flag = 1;
repaint_screen ();
return move_dir;
}
@ -155,7 +155,7 @@ view_file_at_line (const char *filename, int plain_view, int internal,
strcpy (view_entry, "View");
if (regex_command (filename, view_entry, &move_dir) == 0) {
mc_internal_viewer (NULL, filename, &move_dir, start_line);
mcview_viewer (NULL, filename, &move_dir, start_line);
repaint_screen ();
}
} else {
@ -288,7 +288,7 @@ filtered_view_cmd (void)
if (!command)
return;
mc_internal_viewer (command, "", NULL, 0);
mcview_viewer (command, "", NULL, 0);
g_free (command);
}

View File

@ -38,12 +38,12 @@
#include "main.h"
#include "wtools.h"
#include "ext.h"
#include "view.h"
#include "execute.h"
#include "history.h"
#include "cons.saver.h"
#include "layout.h"
#include "../src/search/search.h"
#include "../src/viewer/mcviewer.h"
/* If set, we execute the file command to check the file type */
int use_file_to_check_type = 1;
@ -76,8 +76,8 @@ exec_extension (const char *filename, const char *data, int *move_dir,
int parameter_found = 0;
char prompt[80];
int run_view = 0;
int def_hex_mode = default_hex_mode, changed_hex_mode = 0;
int def_nroff_flag = default_nroff_flag, changed_nroff_flag = 0;
int def_hex_mode = mcview_default_hex_mode, changed_hex_mode = 0;
int def_nroff_flag = mcview_default_nroff_flag, changed_nroff_flag = 0;
int written_nonspace = 0;
int is_cd = 0;
char buffer[1024];
@ -234,26 +234,26 @@ exec_extension (const char *filename, const char *data, int *move_dir,
}
if (run_view) {
altered_hex_mode = 0;
altered_nroff_flag = 0;
if (def_hex_mode != default_hex_mode)
mcview_altered_hex_mode = 0;
mcview_altered_nroff_flag = 0;
if (def_hex_mode != mcview_default_hex_mode)
changed_hex_mode = 1;
if (def_nroff_flag != default_nroff_flag)
if (def_nroff_flag != mcview_default_nroff_flag)
changed_nroff_flag = 1;
/* If we've written whitespace only, then just load filename
* into view
*/
if (written_nonspace) {
mc_internal_viewer (cmd, filename, move_dir, start_line);
mcview_viewer (cmd, filename, move_dir, start_line);
unlink (file_name);
} else {
mc_internal_viewer (NULL, filename, move_dir, start_line);
mcview_viewer (NULL, filename, move_dir, start_line);
}
if (changed_hex_mode && !altered_hex_mode)
default_hex_mode = def_hex_mode;
if (changed_nroff_flag && !altered_nroff_flag)
default_nroff_flag = def_nroff_flag;
if (changed_hex_mode && !mcview_altered_hex_mode)
mcview_default_hex_mode = def_hex_mode;
if (changed_nroff_flag && !mcview_altered_nroff_flag)
mcview_default_nroff_flag = def_nroff_flag;
repaint_screen ();
} else if (is_cd) {
char *q;

View File

@ -287,7 +287,7 @@ find_parameters (char **start_dir, char **pattern, char **content)
const char *content_case_label = N_("Case sens&itive");
const char *content_regexp_label = N_("Re&gular expression");
const char *content_first_hit_label = N_("Fir&st hit");
const char *content_whole_words_label = N_("Whole &words");
const char *content_whole_words_label = N_("&Whole words");
const char *content_all_charsets_label = N_("All cha&rsets");
const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };

View File

@ -72,7 +72,8 @@
#include "cons.saver.h"
#include "layout.h"
#include "info.h" /* The Info widget */
#include "view.h" /* The view widget */
#include "../src/viewer/mcviewer.h" /* The view widget */
#include "setup.h" /* For save_setup() */
#include "../vfs/vfs.h" /* For vfs_translate_url() */
@ -927,7 +928,7 @@ set_display_type (int num, int type)
break;
case view_quick:
new_widget = (Widget *) view_new (0, 0, 0, 0, 1);
new_widget = (Widget *) mcview_new (0, 0, 0, 0, 1);
the_other_panel = (WPanel *) panels [the_other].widget;
if (the_other_panel)
file_name =
@ -935,7 +936,7 @@ set_display_type (int num, int type)
else
file_name = "";
view_load ((WView *) new_widget, 0, file_name, 0);
mcview_load ((struct mcview_struct *) new_widget, 0, file_name, 0);
break;
}

View File

@ -40,7 +40,7 @@
#include "tree.h" /* xtree_mode */
#include "../src/mcconfig/mcconfig.h"
#include "setup.h"
#include "view.h" /* For the externs */
#include "../src/viewer/mcviewer.h" /* For the externs */
#include "hotlist.h" /* load/save/done hotlist */
#include "panelize.h" /* load/save/done panelize */
#include "layout.h"
@ -177,16 +177,16 @@ static const struct {
{ "use_8th_bit_as_meta", &use_8th_bit_as_meta },
{ "confirm_view_dir", &confirm_view_dir },
{ "mouse_move_pages", &mouse_move_pages },
{ "mouse_move_pages_viewer", &mouse_move_pages_viewer },
{ "mouse_move_pages_viewer", &mcview_mouse_move_pages },
{ "mouse_close_dialog", &mouse_close_dialog},
{ "fast_refresh", &fast_refresh },
{ "navigate_with_arrows", &navigate_with_arrows },
{ "drop_menus", &drop_menus },
{ "wrap_mode", &global_wrap_mode},
{ "wrap_mode", &mcview_global_wrap_mode},
{ "old_esc_mode", &old_esc_mode },
{ "cd_symlinks", &cd_symlinks },
{ "show_all_if_ambiguous", &show_all_if_ambiguous },
{ "max_dirt_limit", &max_dirt_limit },
{ "max_dirt_limit", &mcview_max_dirt_limit },
{ "torben_fj_mode", &torben_fj_mode },
{ "use_file_to_guess_type", &use_file_to_check_type },
{ "alternate_plus_minus", &alternate_plus_minus },

View File

@ -48,7 +48,7 @@
#include "dialog.h"
#include "widget.h"
#include "wtools.h"
#include "view.h" /* for default_* externs */
#include "../src/viewer/mcviewer.h" /* for default_* externs */
#define MAX_ENTRIES 16
#define MAX_ENTRY_LEN 60
@ -90,16 +90,16 @@ int check_format_view (const char *p)
if (*q == '{'){
for (q++;*q && *q != '}';q++) {
if (!strncmp (q, "ascii", 5)) {
default_hex_mode = 0;
mcview_default_hex_mode = 0;
q += 4;
} else if (!strncmp (q, "hex", 3)) {
default_hex_mode = 1;
mcview_default_hex_mode = 1;
q += 2;
} else if (!strncmp (q, "nroff", 5)) {
default_nroff_flag = 1;
mcview_default_nroff_flag = 1;
q += 4;
} else if (!strncmp (q, "unform", 6)) {
default_nroff_flag = 0;
mcview_default_nroff_flag = 0;
q += 5;
}
}
@ -694,7 +694,7 @@ execute_menu_command (WEdit *edit_widget, const char *commands)
chmod (file_name, S_IRWXU);
if (run_view) {
run_view = 0;
mc_internal_viewer (file_name, NULL, &run_view, 0);
mcview_viewer (file_name, NULL, &run_view, 0);
} else {
/* execute the command indirectly to allow execution even
* on no-exec filesystems. */

3990
src/view.c

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +0,0 @@
/** \file view.h
* \brief Header: internal file viewer
*/
#ifndef MC_VIEW_H
#define MC_VIEW_H
typedef struct WView WView; /* Can be cast to Widget */
/* Creates a new WView object with the given properties. Caveat: the
* origin is in y-x order, while the extent is in x-y order. */
extern WView *view_new (int y, int x, int cols, int lines, int is_panel);
/* If {command} is not NULL, loads the output of the shell command
* {command} and ignores {file}. If {command} is NULL, loads the
* {file}. If the {file} is also NULL, loads nothing. If {start_line}
* is positive, the output is shown starting in that line. */
extern int view_load (WView *view, const char *command, const char *file,
int start_line);
/* Shows {file} or the output of {command} in the internal viewer,
* starting in line {start_line}. {ret_move_direction} may be NULL or
* point to a variable that will receive the direction in which the user
* wants to move (-1 = previous file, 1 = next file, 0 = do nothing).
*/
extern int mc_internal_viewer (const char *command, const char *file,
int *ret_move_direction, int start_line);
extern int mouse_move_pages_viewer;
extern int max_dirt_limit;
extern int global_wrap_mode;
extern int default_hex_mode;
extern int default_magic_flag;
extern int default_nroff_flag;
extern int altered_hex_mode;
extern int altered_magic_flag;
extern int altered_nroff_flag;
extern int mcview_remember_file_position;
#endif

25
src/viewer/Makefile.am Normal file
View File

@ -0,0 +1,25 @@
noinst_LTLIBRARIES = libmcviewer.la
libmcviewer_la_SOURCES = \
actions_cmd.c \
coord_cache.c \
datasource.c \
dialogs.c \
display.c \
growbuf.c \
hex.c \
inlines.h \
internal.h \
lib.c \
mcviewer.c \
mcviewer.h \
move.c \
nroff.c \
plain.c \
search.c
libmcviewer_la_CFLAGS=-I../ -I$(top_srcdir)/src \
$(GLIB_CFLAGS) \
-DDATADIR=\""$(pkgdatadir)/"\" -DLOCALEDIR=\""$(localedir)"\"

627
src/viewer/actions_cmd.c Normal file
View File

@ -0,0 +1,627 @@
/*
Internal file viewer for the Midnight Commander
Callback function for some actions (hotkeys, menu)
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.
*/
/*
The functions in this section can be bound to hotkeys. They are all
of the same type (taking a pointer to mcview_t as parameter and
returning void). TODO: In the not-too-distant future, these commands
will become fully configurable, like they already are in the
internal editor. By convention, all the function names end in
"_cmd".
*/
#include <config.h>
#include <errno.h>
#include <stdlib.h>
#include "../src/global.h"
#include "../src/panel.h"
#include "../src/layout.h"
#include "../src/wtools.h"
#include "../src/history.h"
#include "../src/charsets.h"
#include "../src/tty/tty.h"
#include "../src/tty/key.h"
#include "../src/cmd.h"
#include "../src/execute.h"
#include "../src/help.h"
#include "internal.h"
#include "mcviewer.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
static void
mcview_continue_search_cmd (mcview_t * view)
{
if (view->last_search_string != NULL) {
mcview_do_search (view);
} else {
/* if not... then ask for an expression */
mcview_search_cmd (view);
}
}
/* --------------------------------------------------------------------------------------------- */
static cb_ret_t
mcview_handle_editkey (mcview_t * view, int key)
{
struct hexedit_change_node *node;
int byte_val;
/* Has there been a change at this position? */
node = view->change_list;
while (node && (node->offset != view->hex_cursor))
node = node->next;
if (!view->hexview_in_text) {
/* Hex editing */
unsigned int hexvalue = 0;
if (key >= '0' && key <= '9')
hexvalue = 0 + (key - '0');
else if (key >= 'A' && key <= 'F')
hexvalue = 10 + (key - 'A');
else if (key >= 'a' && key <= 'f')
hexvalue = 10 + (key - 'a');
else
return MSG_NOT_HANDLED;
if (node)
byte_val = node->value;
else
mcview_get_byte (view, view->hex_cursor, &byte_val);
if (view->hexedit_lownibble) {
byte_val = (byte_val & 0xf0) | (hexvalue);
} else {
byte_val = (byte_val & 0x0f) | (hexvalue << 4);
}
} else {
/* Text editing */
if (key < 256 && ((key == '\n') || is_printable (key)))
byte_val = key;
else
return MSG_NOT_HANDLED;
}
if (!node) {
node = g_new (struct hexedit_change_node, 1);
node->offset = view->hex_cursor;
node->value = byte_val;
mcview_enqueue_change (&view->change_list, node);
} else {
node->value = byte_val;
}
view->dirty++;
mcview_update (view);
mcview_move_right (view, 1);
return MSG_HANDLED;
}
/* --------------------------------------------------------------------------------------------- */
/* Check for left and right arrows, possibly with modifiers */
static cb_ret_t
mcview_check_left_right_keys (mcview_t * view, int c)
{
if (c == KEY_LEFT) {
mcview_move_left (view, 1);
return MSG_HANDLED;
}
if (c == KEY_RIGHT) {
mcview_move_right (view, 1);
return MSG_HANDLED;
}
/* Ctrl with arrows moves by 10 postions in the unwrap mode */
if (view->hex_mode || view->text_wrap_mode)
return MSG_NOT_HANDLED;
if (c == (KEY_M_CTRL | KEY_LEFT)) {
if (view->dpy_text_column >= 10)
view->dpy_text_column -= 10;
else
view->dpy_text_column = 0;
view->dirty++;
return MSG_HANDLED;
}
if (c == (KEY_M_CTRL | KEY_RIGHT)) {
if (view->dpy_text_column <= OFFSETTYPE_MAX - 10)
view->dpy_text_column += 10;
else
view->dpy_text_column = OFFSETTYPE_MAX;
view->dirty++;
return MSG_HANDLED;
}
return MSG_NOT_HANDLED;
}
/* --------------------------------------------------------------------------------------------- */
static void
mcview_cmk_move_up (void *w, int n)
{
mcview_move_up ((mcview_t *) w, n);
}
/* --------------------------------------------------------------------------------------------- */
static void
mcview_cmk_move_down (void *w, int n)
{
mcview_move_down ((mcview_t *) w, n);
}
/* --------------------------------------------------------------------------------------------- */
static void
mcview_cmk_moveto_top (void *w, int n)
{
(void) &n;
mcview_moveto_top ((mcview_t *) w);
}
/* --------------------------------------------------------------------------------------------- */
static void
mcview_cmk_moveto_bottom (void *w, int n)
{
(void) &n;
mcview_moveto_bottom ((mcview_t *) w);
}
/* --------------------------------------------------------------------------------------------- */
static void
mcview_hook (void *v)
{
mcview_t *view = (mcview_t *) v;
WPanel *panel;
/* If the user is busy typing, wait until he finishes to update the
screen */
if (!is_idle ()) {
if (!hook_present (idle_hook, mcview_hook))
add_hook (&idle_hook, mcview_hook, v);
return;
}
delete_hook (&idle_hook, mcview_hook);
if (get_current_type () == view_listing)
panel = current_panel;
else if (get_other_type () == view_listing)
panel = other_panel;
else
return;
mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0);
mcview_display (view);
}
/* --------------------------------------------------------------------------------------------- */
/* Both views */
static cb_ret_t
mcview_handle_key (mcview_t * view, int c)
{
c = convert_from_input_c (c);
if (view->hex_mode) {
switch (c) {
case '\t':
view->hexview_in_text = !view->hexview_in_text;
view->dirty++;
return MSG_HANDLED;
case XCTRL ('a'):
mcview_moveto_bol (view);
view->dirty++;
return MSG_HANDLED;
case XCTRL ('b'):
mcview_move_left (view, 1);
return MSG_HANDLED;
case XCTRL ('e'):
mcview_moveto_eol (view);
return MSG_HANDLED;
case XCTRL ('f'):
mcview_move_right (view, 1);
return MSG_HANDLED;
}
if (view->hexedit_mode && mcview_handle_editkey (view, c) == MSG_HANDLED)
return MSG_HANDLED;
}
if (mcview_check_left_right_keys (view, c))
return MSG_HANDLED;
if (check_movement_keys (c, view->data_area.height + 1, view,
mcview_cmk_move_up, mcview_cmk_move_down,
mcview_cmk_moveto_top, mcview_cmk_moveto_bottom))
return MSG_HANDLED;
switch (c) {
case '?':
case '/':
view->search_type = MC_SEARCH_T_REGEX;
mcview_search_cmd (view);
return MSG_HANDLED;
break;
/* Continue search */
case XCTRL ('r'):
case XCTRL ('s'):
case 'n':
case KEY_F (17):
mcview_continue_search_cmd (view);
return MSG_HANDLED;
/* toggle ruler */
case ALT ('r'):
mcview_toggle_ruler_cmd (view);
return MSG_HANDLED;
case 'h':
mcview_move_left (view, 1);
return MSG_HANDLED;
case 'j':
case '\n':
case 'e':
mcview_move_down (view, 1);
return MSG_HANDLED;
case 'd':
mcview_move_down (view, (view->data_area.height + 1) / 2);
return MSG_HANDLED;
case 'u':
mcview_move_up (view, (view->data_area.height + 1) / 2);
return MSG_HANDLED;
case 'k':
case 'y':
mcview_move_up (view, 1);
return MSG_HANDLED;
case 'l':
mcview_move_right (view, 1);
return MSG_HANDLED;
case ' ':
case 'f':
mcview_move_down (view, view->data_area.height);
return MSG_HANDLED;
case XCTRL ('o'):
view_other_cmd ();
return MSG_HANDLED;
/* Unlike Ctrl-O, run a new shell if the subshell is not running. */
case '!':
exec_shell ();
return MSG_HANDLED;
case 'b':
mcview_move_up (view, view->data_area.height);
return MSG_HANDLED;
case KEY_IC:
mcview_move_up (view, 2);
return MSG_HANDLED;
case KEY_DC:
mcview_move_down (view, 2);
return MSG_HANDLED;
case 'm':
view->marks[view->marker] = view->dpy_start;
return MSG_HANDLED;
case 'r':
view->dpy_start = view->marks[view->marker];
view->dirty++;
return MSG_HANDLED;
/* Use to indicate parent that we want to see the next/previous file */
/* Does not work in panel mode */
case XCTRL ('f'):
case XCTRL ('b'):
if (!mcview_is_in_panel (view))
view->move_dir = c == XCTRL ('f') ? 1 : -1;
/* FALLTHROUGH */
case 'q':
case XCTRL ('g'):
case ESC_CHAR:
if (mcview_ok_to_quit (view))
view->want_to_quit = TRUE;
return MSG_HANDLED;
case XCTRL ('t'):
mcview_select_encoding (view);
view->dirty++;
mcview_update (view);
return MSG_HANDLED;
#ifdef MC_ENABLE_DEBUGGING_CODE
case 't': /* mnemonic: "test" */
mcview_ccache_dump (view);
return MSG_HANDLED;
#endif
}
if (c >= '0' && c <= '9')
view->marker = c - '0';
/* Key not used */
return MSG_NOT_HANDLED;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
cb_ret_t
mcview_callback (Widget * w, widget_msg_t msg, int parm)
{
mcview_t *view = (mcview_t *) w;
cb_ret_t i;
Dlg_head *h = view->widget.parent;
mcview_compute_areas (view);
mcview_update_bytes_per_line (view);
switch (msg) {
case WIDGET_INIT:
if (mcview_is_in_panel (view))
add_hook (&select_file_hook, mcview_hook, view);
else
view->dpy_bbar_dirty = TRUE;
return MSG_HANDLED;
case WIDGET_DRAW:
mcview_display (view);
return MSG_HANDLED;
case WIDGET_CURSOR:
if (view->hex_mode)
mcview_place_cursor (view);
return MSG_HANDLED;
case WIDGET_KEY:
i = mcview_handle_key ((mcview_t *) view, parm);
if (view->want_to_quit && !mcview_is_in_panel (view))
dlg_stop (h);
else {
mcview_update (view);
}
return i;
case WIDGET_FOCUS:
view->dpy_bbar_dirty = TRUE;
mcview_update (view);
return MSG_HANDLED;
case WIDGET_DESTROY:
mcview_done (view);
if (mcview_is_in_panel (view))
delete_hook (&select_file_hook, mcview_hook);
return MSG_HANDLED;
default:
return default_proc (msg, parm);
}
}
/* --------------------------------------------------------------------------------------------- */
cb_ret_t
mcview_dialog_callback (Dlg_head * h, dlg_msg_t msg, int parm)
{
switch (msg) {
case DLG_RESIZE:
mcview_adjust_size (h);
return MSG_HANDLED;
default:
return default_dlg_callback (h, msg, parm);
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_help_cmd (void)
{
interactive_display (NULL, "[Internal File Viewer]");
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_quit_cmd (mcview_t * view)
{
if (mcview_ok_to_quit (view))
dlg_stop (view->widget.parent);
}
/* --------------------------------------------------------------------------------------------- */
/* Toggle between hex view and text view */
void
mcview_toggle_hex_mode_cmd (mcview_t * view)
{
mcview_toggle_hex_mode (view);
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_line_cmd (mcview_t * view)
{
char *answer, *answer_end, prompt_format[BUF_SMALL], prompt[BUF_SMALL];
off_t line, col;
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
g_snprintf (prompt_format, sizeof (prompt_format),
_(" The current address is %s.\n"
" Enter the new address:"), "0x%08" OFFSETTYPE_PRIX "");
g_snprintf (prompt, sizeof (prompt), prompt_format, view->hex_cursor);
answer = input_dialog (_(" Goto line "), prompt, MC_HISTORY_VIEW_GOTO_LINE, "");
if (answer != NULL && answer[0] != '\0') {
errno = 0;
line = strtoul (answer, &answer_end, 10);
if (*answer_end == '\0' && errno == 0 && line >= 1)
mcview_moveto (view, line - 1, 0);
}
g_free (answer);
view->dirty++;
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_addr_cmd (mcview_t * view)
{
char *line, *error, prompt[BUF_SMALL];
off_t addr;
g_snprintf (prompt, sizeof (prompt),
_(" The current address is 0x%lx.\n" " Enter the new address:"),
(long unsigned int) view->hex_cursor);
line = input_dialog (_(" Goto Address "), prompt, MC_HISTORY_VIEW_GOTO_ADDR, "");
if (line != NULL) {
if (*line != '\0') {
addr = strtoul (line, &error, 0);
if ((*error == '\0') && mcview_get_byte (view, addr, NULL) == TRUE) {
mcview_moveto_offset (view, addr);
} else {
message (D_ERROR, _("Warning"), _(" Invalid address "));
}
}
g_free (line);
}
view->dirty++;
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
/* Toggle between hexview and hexedit mode */
void
mcview_toggle_hexedit_mode_cmd (mcview_t * view)
{
mcview_toggle_hexedit_mode (view);
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_hexedit_save_changes_cmd (mcview_t * view)
{
(void) mcview_hexedit_save_changes (view);
}
/* --------------------------------------------------------------------------------------------- */
/* Toggle between wrapped and unwrapped view */
void
mcview_toggle_wrap_mode_cmd (mcview_t * view)
{
mcview_toggle_wrap_mode (view);
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
/* Both views */
void
mcview_search_cmd (mcview_t * view)
{
if (mcview_dialog_search (view))
mcview_do_search (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_magic_mode_cmd (mcview_t * view)
{
mcview_toggle_magic_mode (view);
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_nroff_mode_cmd (mcview_t * view)
{
mcview_toggle_nroff_mode (view);
mcview_update (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_ruler_cmd (mcview_t * view)
{
mcview_display_toggle_ruler (view);
}
/* --------------------------------------------------------------------------------------------- */

329
src/viewer/coord_cache.c Normal file
View File

@ -0,0 +1,329 @@
/*
Internal file viewer for the Midnight Commander
Function for work with coordinate cache (ccache)
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.
*/
/*
This cache provides you with a fast lookup to map file offsets into
line/column pairs and vice versa. The interface to the mapping is
provided by the functions mcview_coord_to_offset() and
mcview_offset_to_coord().
The cache is implemented as a simple sorted array holding entries
that map some of the offsets to their line/column pair. Entries that
are not cached themselves are interpolated (exactly) from their
neighbor entries. The algorithm used for determining the line/column
for a specific offset needs to be kept synchronized with the one used
in display().
*/
#include <config.h>
#include "../src/global.h"
#include "../src/tty/tty.h"
#include "internal.h"
#define VIEW_COORD_CACHE_GRANUL 1024
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_coord_cache_entry_less (const struct coord_cache_entry *a,
const struct coord_cache_entry *b, enum ccache_type crit,
gboolean nroff_mode)
{
if (crit == CCACHE_OFFSET)
return (a->cc_offset < b->cc_offset);
if (a->cc_line < b->cc_line)
return TRUE;
if (a->cc_line == b->cc_line) {
if (nroff_mode) {
return (a->cc_nroff_column < b->cc_nroff_column);
} else {
return (a->cc_column < b->cc_column);
}
}
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
#ifdef MC_ENABLE_DEBUGGING_CODE
void
mcview_ccache_dump (mcview_t * view)
{
FILE *f;
off_t offset, line, column, nextline_offset, filesize;
guint i;
const struct coord_cache_entry *cache;
assert (view->coord_cache != NULL);
filesize = mcview_get_filesize (view);
cache = &(g_array_index (view->coord_cache, struct coord_cache_entry, 0));
f = fopen ("mcview-ccache.out", "w");
if (f == NULL)
return;
(void) setvbuf (f, NULL, _IONBF, 0);
/* cache entries */
for (i = 0; i < view->coord_cache->len; i++) {
(void) fprintf (f,
"entry %8u "
"offset %8" OFFSETTYPE_PRId " "
"line %8" OFFSETTYPE_PRId " "
"column %8" OFFSETTYPE_PRId " "
"nroff_column %8" OFFSETTYPE_PRId "\n",
(unsigned int) i, cache[i].cc_offset, cache[i].cc_line,
cache[i].cc_column, cache[i].cc_nroff_column);
}
(void) fprintf (f, "\n");
/* offset -> line/column translation */
for (offset = 0; offset < filesize; offset++) {
mcview_offset_to_coord (view, &line, &column, offset);
(void) fprintf (f,
"offset %8" OFFSETTYPE_PRId " "
"line %8" OFFSETTYPE_PRId " "
"column %8" OFFSETTYPE_PRId "\n", offset, line, column);
}
/* line/column -> offset translation */
for (line = 0; TRUE; line++) {
mcview_coord_to_offset (view, &nextline_offset, line + 1, 0);
(void) fprintf (f, "nextline_offset %8" OFFSETTYPE_PRId "\n", nextline_offset);
for (column = 0; TRUE; column++) {
mcview_coord_to_offset (view, &offset, line, column);
if (offset >= nextline_offset)
break;
(void) fprintf (f,
"line %8" OFFSETTYPE_PRId " column %8" OFFSETTYPE_PRId " offset %8"
OFFSETTYPE_PRId "\n", line, column, offset);
}
if (nextline_offset >= filesize - 1)
break;
}
(void) fclose (f);
}
#endif
/* --------------------------------------------------------------------------------------------- */
/* Find and return the index of the last cache entry that is
* smaller than ''coord'', according to the criterion ''sort_by''. */
guint
mcview_ccache_find (mcview_t * view, const struct coord_cache_entry *cache,
const struct coord_cache_entry *coord, enum ccache_type sort_by)
{
guint base, i, limit;
limit = view->coord_cache->len;
assert (limit != 0);
base = 0;
while (limit > 1) {
i = base + limit / 2;
if (mcview_coord_cache_entry_less (coord, &cache[i], sort_by, view->text_nroff_mode)) {
/* continue the search in the lower half of the cache */
} else {
/* continue the search in the upper half of the cache */
base = i;
}
limit = (limit + 1) / 2;
}
return base;
}
/* --------------------------------------------------------------------------------------------- */
/* Look up the missing components of ''coord'', which are given by
* ''lookup_what''. The function returns the smallest value that
* matches the existing components of ''coord''.
*/
void
mcview_ccache_lookup (mcview_t * view, struct coord_cache_entry *coord,
enum ccache_type lookup_what)
{
guint i;
struct coord_cache_entry *cache, current, next, entry;
enum ccache_type sorter;
off_t limit;
enum {
NROFF_START,
NROFF_BACKSPACE,
NROFF_CONTINUATION
} nroff_state;
if (!view->coord_cache) {
view->coord_cache = g_array_new (FALSE, FALSE, sizeof (struct coord_cache_entry));
current.cc_offset = 0;
current.cc_line = 0;
current.cc_column = 0;
current.cc_nroff_column = 0;
g_array_append_val (view->coord_cache, current);
}
sorter = (lookup_what == CCACHE_OFFSET) ? CCACHE_LINECOL : CCACHE_OFFSET;
tty_enable_interrupt_key ();
retry:
/* find the two neighbor entries in the cache */
cache = &(g_array_index (view->coord_cache, struct coord_cache_entry, 0));
i = mcview_ccache_find (view, cache, coord, sorter);
/* now i points to the lower neighbor in the cache */
current = cache[i];
if (i + 1 < view->coord_cache->len)
limit = cache[i + 1].cc_offset;
else
limit = current.cc_offset + VIEW_COORD_CACHE_GRANUL;
entry = current;
nroff_state = NROFF_START;
for (; current.cc_offset < limit; current = next) {
int c, nextc;
if (! mcview_get_byte (view, current.cc_offset, &c))
break;
if (!mcview_coord_cache_entry_less (&current, coord, sorter, view->text_nroff_mode)) {
if (lookup_what == CCACHE_OFFSET && view->text_nroff_mode && nroff_state != NROFF_START) {
/* don't break here */
} else {
break;
}
}
/* Provide useful default values for ''next'' */
next.cc_offset = current.cc_offset + 1;
next.cc_line = current.cc_line;
next.cc_column = current.cc_column + 1;
next.cc_nroff_column = current.cc_nroff_column + 1;
/* and override some of them as necessary. */
if (c == '\r') {
mcview_get_byte_indexed (view, current.cc_offset, 1, &nextc);
/* Ignore '\r' if it is followed by '\r' or '\n'. If it is
* followed by anything else, it is a Mac line ending and
* produces a line break.
*/
if (nextc == '\r' || nextc == '\n') {
next.cc_column = current.cc_column;
next.cc_nroff_column = current.cc_nroff_column;
} else {
next.cc_line = current.cc_line + 1;
next.cc_column = 0;
next.cc_nroff_column = 0;
}
} else if (nroff_state == NROFF_BACKSPACE) {
next.cc_nroff_column = current.cc_nroff_column - 1;
} else if (c == '\t') {
next.cc_column = mcview_offset_rounddown (current.cc_column, 8) + 8;
next.cc_nroff_column = mcview_offset_rounddown (current.cc_nroff_column, 8) + 8;
} else if (c == '\n') {
next.cc_line = current.cc_line + 1;
next.cc_column = 0;
next.cc_nroff_column = 0;
} else {
/* Use all default values from above */
}
switch (nroff_state) {
case NROFF_START:
case NROFF_CONTINUATION:
if (mcview_is_nroff_sequence (view, current.cc_offset))
nroff_state = NROFF_BACKSPACE;
else
nroff_state = NROFF_START;
break;
case NROFF_BACKSPACE:
nroff_state = NROFF_CONTINUATION;
break;
}
/* Cache entries must guarantee that for each i < j,
* line[i] <= line[j] and column[i] < column[j]. In the case of
* nroff sequences and '\r' characters, this is not guaranteed,
* so we cannot save them. */
if (nroff_state == NROFF_START && c != '\r')
entry = next;
}
if (i + 1 == view->coord_cache->len && entry.cc_offset != cache[i].cc_offset) {
g_array_append_val (view->coord_cache, entry);
if (!tty_got_interrupt ())
goto retry;
}
tty_disable_interrupt_key ();
if (lookup_what == CCACHE_OFFSET) {
coord->cc_offset = current.cc_offset;
} else {
coord->cc_line = current.cc_line;
coord->cc_column = current.cc_column;
coord->cc_nroff_column = current.cc_nroff_column;
}
}
/* --------------------------------------------------------------------------------------------- */

397
src/viewer/datasource.c Normal file
View File

@ -0,0 +1,397 @@
/*
Internal file viewer for the Midnight Commander
Functions for datasources
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.
*/
/*
The data source provides the viewer with data from either a file, a
string or the output of a command. The mcview_get_byte() function can be
used to get the value of a byte at a specific offset. If the offset
is out of range, -1 is returned. The function mcview_get_byte_indexed(a,b)
returns the byte at the offset a+b, or -1 if a+b is out of range.
The mcview_set_byte() function has the effect that later calls to
mcview_get_byte() will return the specified byte for this offset. This
function is designed only for use by the hexedit component after
saving its changes. Inspect the source before you want to use it for
other purposes.
The mcview_get_filesize() function returns the current size of the
data source. If the growing buffer is used, this size may increase
later on. Use the mcview_may_still_grow() function when you want to
know if the size can change later.
*/
#include <config.h>
#include "../src/global.h"
#include "../src/wtools.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
static void
mcview_set_datasource_stdio_pipe (mcview_t * view, FILE * fp)
{
assert (fp != NULL);
view->datasource = DS_STDIO_PIPE;
view->ds_stdio_pipe = fp;
mcview_growbuf_init (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_set_datasource_none (mcview_t * view)
{
view->datasource = DS_NONE;
}
/* --------------------------------------------------------------------------------------------- */
off_t
mcview_get_filesize (mcview_t * view)
{
switch (view->datasource) {
case DS_NONE:
return 0;
case DS_STDIO_PIPE:
case DS_VFS_PIPE:
return mcview_growbuf_filesize (view);
case DS_FILE:
return view->ds_file_filesize;
case DS_STRING:
return view->ds_string_len;
default:
assert (!"Unknown datasource type");
return 0;
}
}
/* --------------------------------------------------------------------------------------------- */
char *
mcview_get_ptr_file (mcview_t * view, off_t byte_index)
{
assert (view->datasource == DS_FILE);
mcview_file_load_data (view, byte_index);
if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
return (char *) (view->ds_file_data + (byte_index - view->ds_file_offset));
return NULL;
}
/* --------------------------------------------------------------------------------------------- */
char *
mcview_get_ptr_string (mcview_t * view, off_t byte_index)
{
assert (view->datasource == DS_STRING);
if (byte_index < view->ds_string_len)
return (char *) (view->ds_string_data + byte_index);
return NULL;
}
/* --------------------------------------------------------------------------------------------- */
int
mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * result)
{
gchar *str = NULL;
int res = -1;
gunichar ch;
gchar *next_ch = NULL;
int width = 0;
*result = TRUE;
switch (view->datasource) {
case DS_STDIO_PIPE:
case DS_VFS_PIPE:
str = mcview_get_ptr_growing_buffer (view, byte_index);
break;
case DS_FILE:
str = mcview_get_ptr_file (view, byte_index);
break;
case DS_STRING:
str = mcview_get_ptr_string (view, byte_index);
break;
case DS_NONE:
break;
}
if (str == NULL) {
*result = FALSE;
width = 0;
return 0;
}
res = g_utf8_get_char_validated (str, -1);
if (res < 0) {
ch = *str;
width = 0;
} else {
ch = res;
/* Calculate UTF-8 char width */
next_ch = g_utf8_next_char (str);
if (next_ch) {
width = next_ch - str;
} else {
ch = 0;
width = 0;
}
}
*char_width = width;
return ch;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_get_byte_string (mcview_t * view, off_t byte_index, int *retval)
{
assert (view->datasource == DS_STRING);
if (byte_index < view->ds_string_len) {
if (retval)
*retval = view->ds_string_data[byte_index];
return TRUE;
}
if (retval)
*retval = -1;
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_get_byte_none (mcview_t * view, off_t byte_index, int *retval)
{
assert (view->datasource == DS_NONE);
(void) &view;
(void) byte_index;
if (retval)
*retval = -1;
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_set_byte (mcview_t * view, off_t offset, byte b)
{
(void) &b;
assert (offset < mcview_get_filesize (view));
assert (view->datasource == DS_FILE);
view->ds_file_datalen = 0; /* just force reloading */
}
/* --------------------------------------------------------------------------------------------- */
/*static inline*/
void
mcview_file_load_data (mcview_t * view, off_t byte_index)
{
off_t blockoffset;
ssize_t res;
size_t bytes_read;
assert (view->datasource == DS_FILE);
if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
return;
if (byte_index >= view->ds_file_filesize)
return;
blockoffset = mcview_offset_rounddown (byte_index, view->ds_file_datasize);
if (mc_lseek (view->ds_file_fd, blockoffset, SEEK_SET) == -1)
goto error;
bytes_read = 0;
while (bytes_read < view->ds_file_datasize) {
res =
mc_read (view->ds_file_fd, view->ds_file_data + bytes_read,
view->ds_file_datasize - bytes_read);
if (res == -1)
goto error;
if (res == 0)
break;
bytes_read += (size_t) res;
}
view->ds_file_offset = blockoffset;
if (bytes_read > view->ds_file_filesize - view->ds_file_offset) {
/* the file has grown in the meantime -- stick to the old size */
view->ds_file_datalen = view->ds_file_filesize - view->ds_file_offset;
} else {
view->ds_file_datalen = bytes_read;
}
return;
error:
view->ds_file_datalen = 0;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_close_datasource (mcview_t * view)
{
switch (view->datasource) {
case DS_NONE:
break;
case DS_STDIO_PIPE:
if (view->ds_stdio_pipe != NULL) {
(void) pclose (view->ds_stdio_pipe);
mcview_display (view);
close_error_pipe (D_NORMAL, NULL);
view->ds_stdio_pipe = NULL;
}
mcview_growbuf_free (view);
break;
case DS_VFS_PIPE:
if (view->ds_vfs_pipe != -1) {
(void) mc_close (view->ds_vfs_pipe);
view->ds_vfs_pipe = -1;
}
mcview_growbuf_free (view);
break;
case DS_FILE:
(void) mc_close (view->ds_file_fd);
view->ds_file_fd = -1;
g_free (view->ds_file_data);
view->ds_file_data = NULL;
break;
case DS_STRING:
g_free (view->ds_string_data);
view->ds_string_data = NULL;
break;
default:
assert (!"Unknown datasource type");
}
view->datasource = DS_NONE;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_set_datasource_file (mcview_t * view, int fd, const struct stat *st)
{
view->datasource = DS_FILE;
view->ds_file_fd = fd;
view->ds_file_filesize = st->st_size;
view->ds_file_offset = 0;
view->ds_file_data = g_malloc (4096);
view->ds_file_datalen = 0;
view->ds_file_datasize = 4096;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_load_command_output (mcview_t * view, const char *command)
{
FILE *fp;
mcview_close_datasource (view);
open_error_pipe ();
if ((fp = popen (command, "r")) == NULL) {
/* Avoid two messages. Message from stderr has priority. */
mcview_display (view);
if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL))
mcview_show_error (view, _(" Cannot spawn child process "));
return FALSE;
}
/* First, check if filter produced any output */
mcview_set_datasource_stdio_pipe (view, fp);
if (! mcview_get_byte (view, 0, NULL)) {
mcview_close_datasource (view);
/* Avoid two messages. Message from stderr has priority. */
mcview_display (view);
if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL))
mcview_show_error (view, _("Empty output from child filter"));
return FALSE;
} else {
/*
* At least something was read correctly. Close stderr and let
* program die if it will try to write something there.
*
* Ideally stderr should be read asynchronously to prevent programs
* from blocking (poll/select multiplexor).
*/
close_error_pipe (D_NORMAL, NULL);
}
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_set_datasource_vfs_pipe (mcview_t * view, int fd)
{
assert (fd != -1);
view->datasource = DS_VFS_PIPE;
view->ds_vfs_pipe = fd;
mcview_growbuf_init (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_set_datasource_string (mcview_t * view, const char *s)
{
view->datasource = DS_STRING;
view->ds_string_data = (byte *) g_strdup (s);
view->ds_string_len = strlen (s);
}
/* --------------------------------------------------------------------------------------------- */

188
src/viewer/dialogs.c Normal file
View File

@ -0,0 +1,188 @@
/*
Internal file viewer for the Midnight Commander
Function for paint dialogs
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 "../src/global.h"
#include "../src/wtools.h"
#include "internal.h"
#include "../src/charsets.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_dialog_search (mcview_t * view)
{
enum {
SEARCH_DLG_MIN_HEIGHT = 11,
SEARCH_DLG_HEIGHT_SUPPLY = 3,
SEARCH_DLG_WIDTH = 58
};
char *defval = g_strdup (view->last_search_string != NULL ? view->last_search_string : "");
char *exp = NULL;
#ifdef HAVE_CHARSET
GString *tmp;
#endif
int ttype_of_search = (int) view->search_type;
int tall_codepages = (int) view->search_all_codepages;
int tsearch_case = (int) view->search_case;
int twhole_words = (int) view->whole_words;
int tsearch_backwards = (int) view->search_backwards;
int qd_result;
gchar **list_of_types = mc_search_get_types_strings_array ();
int SEARCH_DLG_HEIGHT =
SEARCH_DLG_MIN_HEIGHT + g_strv_length (list_of_types) - SEARCH_DLG_HEIGHT_SUPPLY;
QuickWidget quick_widgets[] = {
{quick_button, 6, 10, SEARCH_DLG_HEIGHT - 3, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0,
B_CANCEL, 0, 0, NULL, NULL, NULL},
{quick_button, 2, 10, SEARCH_DLG_HEIGHT - 3, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER,
0, 0, NULL, NULL, NULL},
#ifdef HAVE_CHARSET
{quick_checkbox, SEARCH_DLG_WIDTH / 2 + 3, SEARCH_DLG_WIDTH, 7, SEARCH_DLG_HEIGHT,
N_("All charsets"), 0, 0,
&tall_codepages, 0, NULL, NULL, NULL},
#endif
{quick_checkbox, SEARCH_DLG_WIDTH / 2 + 3, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT,
N_("&Whole words"), 0, 0, &twhole_words, 0, NULL, NULL, NULL},
{quick_checkbox, SEARCH_DLG_WIDTH / 2 + 3, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT,
N_("&Backwards"), 0, 0, &tsearch_backwards, 0, NULL, NULL, NULL},
{quick_checkbox, SEARCH_DLG_WIDTH / 2 + 3, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT,
N_("case &Sensitive"), 0, 0,
&tsearch_case, 0, NULL, NULL, NULL},
{quick_radio, 3, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, 0, g_strv_length (list_of_types),
ttype_of_search,
(void *) &ttype_of_search, const_cast (char **, list_of_types), NULL, NULL, NULL},
{quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, defval, 52, 0,
0, &exp, N_("Search"), NULL, NULL},
{quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT,
N_(" Enter search string:"), 0, 0, 0, 0, 0, NULL, NULL},
NULL_QuickWidget
};
QuickDialog Quick_input = {
SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
"[Input Line Keys]", quick_widgets, 0
};
convert_to_display (defval);
qd_result = quick_dialog (&Quick_input);
g_strfreev (list_of_types);
if (qd_result == B_CANCEL) {
g_free (exp);
g_free (defval);
return FALSE;
}
view->search_backwards = tsearch_backwards;
view->search_type = (mc_search_type_t) ttype_of_search;
view->search_all_codepages = (gboolean) tall_codepages;
view->search_case = (gboolean) tsearch_case;
view->whole_words = (gboolean) twhole_words;
if (exp == NULL || exp[0] == '\0') {
g_free (exp);
g_free (defval);
return FALSE;
}
#ifdef HAVE_CHARSET
tmp = str_convert_to_input (exp);
if (tmp) {
g_free (exp);
exp = g_string_free (tmp, FALSE);
}
#endif
g_free (view->last_search_string);
view->last_search_string = exp;
exp = NULL;
if (view->search_nroff_seq)
mcview_nroff_seq_free (&(view->search_nroff_seq));
if (view->search)
mc_search_free (view->search);
view->search = mc_search_new (view->last_search_string, -1);
view->search_nroff_seq = mcview_nroff_seq_new (view);
if (!view->search) {
g_free (exp);
g_free (defval);
return FALSE;
}
view->search->search_type = view->search_type;
view->search->is_all_charsets = view->search_all_codepages;
view->search->is_case_sentitive = view->search_case;
view->search->search_fn = mcview_search_cmd_callback;
view->search->update_fn = mcview_search_update_cmd_callback;
view->search->whole_words = view->whole_words;
g_free (exp);
g_free (defval);
return TRUE;
}

432
src/viewer/display.c Normal file
View File

@ -0,0 +1,432 @@
/*
Internal file viewer for the Midnight Commander
Function for whow info on display
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 "../src/global.h"
#include "../src/tty/color.h"
#include "../src/tty/tty.h"
#include "../src/tty/key.h"
#include "../src/strutil.h"
#include "internal.h"
#include "mcviewer.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/* If set, show a ruler */
static enum ruler_type {
RULER_NONE,
RULER_TOP,
RULER_BOTTOM
} ruler = RULER_NONE;
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
static inline void
mcview_my_define (Dlg_head * h, int idx, const char *text, void (*fn) (mcview_t *), mcview_t * view)
{
buttonbar_set_label_data (h, idx, text, (buttonbarfn) fn, view);
}
/* --------------------------------------------------------------------------------------------- */
/* Define labels and handlers for functional keys */
static void
mcview_labels (mcview_t * view)
{
const char *text;
Dlg_head *h = view->widget.parent;
buttonbar_set_label (h, 1, Q_ ("ButtonBar|Help"), mcview_help_cmd);
mcview_my_define (h, 10, Q_ ("ButtonBar|Quit"), mcview_quit_cmd, view);
text = view->hex_mode ? Q_ ("ButtonBar|Ascii") : Q_ ("ButtonBar|Hex");
mcview_my_define (h, 4, text, mcview_toggle_hex_mode_cmd, view);
text = view->hex_mode ? Q_ ("ButtonBar|Goto") : Q_ ("ButtonBar|Line");
mcview_my_define (h, 5, text,
view->hex_mode ? mcview_moveto_addr_cmd : mcview_moveto_line_cmd, view);
if (view->hex_mode) {
if (view->hexedit_mode) {
mcview_my_define (h, 2, Q_ ("ButtonBar|View"), mcview_toggle_hexedit_mode_cmd, view);
} else if (view->datasource == DS_FILE) {
mcview_my_define (h, 2, Q_ ("ButtonBar|Edit"), mcview_toggle_hexedit_mode_cmd, view);
} else {
buttonbar_clear_label (h, 2);
}
mcview_my_define (h, 6, Q_ ("ButtonBar|Save"), mcview_hexedit_save_changes_cmd, view);
} else {
text = view->text_wrap_mode ? Q_ ("ButtonBar|UnWrap") : Q_ ("ButtonBar|Wrap");
mcview_my_define (h, 2, text, mcview_toggle_wrap_mode_cmd, view);
}
text = view->hex_mode ? Q_ ("ButtonBar|HxSrch") : Q_ ("ButtonBar|Search");
mcview_my_define (h, 7, text, mcview_search_cmd, view);
text = view->magic_mode ? Q_ ("ButtonBar|Raw") : Q_ ("ButtonBar|Parse");
mcview_my_define (h, 8, text, mcview_toggle_magic_mode_cmd, view);
/* don't override the key to access the main menu */
if (!mcview_is_in_panel (view)) {
text = view->text_nroff_mode ? Q_ ("ButtonBar|Unform") : Q_ ("ButtonBar|Format");
mcview_my_define (h, 9, text, mcview_toggle_nroff_mode_cmd, view);
mcview_my_define (h, 3, Q_ ("ButtonBar|Quit"), mcview_quit_cmd, view);
}
}
/* --------------------------------------------------------------------------------------------- */
static void
mcview_display_status (mcview_t * view)
{
const screen_dimen top = view->status_area.top;
const screen_dimen left = view->status_area.left;
const screen_dimen width = view->status_area.width;
const screen_dimen height = view->status_area.height;
const char *file_label, *file_name;
screen_dimen file_label_width;
int i;
char *tmp;
if (height < 1)
return;
tty_setcolor (SELECTED_COLOR);
widget_move (view, top, left);
tty_draw_hline (top, left, ' ', width);
file_label = _("File: %s");
file_label_width = str_term_width1 (file_label) - 2;
file_name = view->filename ? view->filename : view->command ? view->command : "";
if (width < file_label_width + 6)
tty_print_string (str_fit_to_term (file_name, width, J_LEFT_FIT));
else {
i = (width > 22 ? 22 : width) - file_label_width;
tmp = g_strdup_printf (file_label, str_fit_to_term (file_name, i, J_LEFT_FIT));
tty_print_string (tmp);
g_free (tmp);
if (width > 46) {
widget_move (view, top, left + 24);
/* FIXME: the format strings need to be changed when off_t changes */
if (view->hex_mode)
tty_printf (_("Offset 0x%08lx"), (unsigned long) view->hex_cursor);
else {
off_t line, col;
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
tty_printf (_("Line %lu Col %lu"),
(unsigned long) line + 1,
(unsigned long) (view->text_wrap_mode ? col : view->dpy_text_column));
}
}
if (width > 62) {
off_t filesize;
filesize = mcview_get_filesize (view);
widget_move (view, top, left + 43);
if (!mcview_may_still_grow (view)) {
tty_printf (_("%s bytes"), size_trunc (filesize));
} else {
tty_printf (_(">= %s bytes"), size_trunc (filesize));
}
}
if (width > 26) {
mcview_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end);
}
}
tty_setcolor (SELECTED_COLOR);
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_update (mcview_t * view)
{
static int dirt_limit = 1;
if (view->dpy_bbar_dirty) {
view->dpy_bbar_dirty = FALSE;
mcview_labels (view);
buttonbar_redraw (view->widget.parent);
}
if (view->dirty > dirt_limit) {
/* Too many updates skipped -> force a update */
mcview_display (view);
view->dirty = 0;
/* Raise the update skipping limit */
dirt_limit++;
if (dirt_limit > mcview_max_dirt_limit)
dirt_limit = mcview_max_dirt_limit;
}
if (view->dirty) {
if (is_idle ()) {
/* We have time to update the screen properly */
mcview_display (view);
view->dirty = 0;
if (dirt_limit > 1)
dirt_limit--;
} else {
/* We are busy -> skipping full update,
only the status line is updated */
mcview_display_status (view);
}
/* Here we had a refresh, if fast scrolling does not work
restore the refresh, although this should not happen */
}
}
/* --------------------------------------------------------------------------------------------- */
/* Displays as much data from view->dpy_start as fits on the screen */
void
mcview_display (mcview_t * view)
{
mcview_compute_areas (view);
if (view->hex_mode) {
mcview_display_hex (view);
} else if (view->text_nroff_mode) {
mcview_display_nroff (view);
} else {
mcview_display_text (view);
}
mcview_display_status (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_compute_areas (mcview_t * view)
{
struct area view_area;
screen_dimen height, rest, y;
/* The viewer is surrounded by a frame of size view->dpy_frame_size.
* Inside that frame, there are: The status line (at the top),
* the data area and an optional ruler, which is shown above or
* below the data area. */
view_area.top = view->dpy_frame_size;
view_area.left = view->dpy_frame_size;
view_area.height = mcview_dimen_doz (view->widget.lines, 2 * view->dpy_frame_size);
view_area.width = mcview_dimen_doz (view->widget.cols, 2 * view->dpy_frame_size);
/* Most coordinates of the areas equal those of the whole viewer */
view->status_area = view_area;
view->ruler_area = view_area;
view->data_area = view_area;
/* Compute the heights of the areas */
rest = view_area.height;
height = mcview_dimen_min (rest, 1);
view->status_area.height = height;
rest -= height;
height = mcview_dimen_min (rest, (ruler == RULER_NONE || view->hex_mode) ? 0 : 2);
view->ruler_area.height = height;
rest -= height;
view->data_area.height = rest;
/* Compute the position of the areas */
y = view_area.top;
view->status_area.top = y;
y += view->status_area.height;
if (ruler == RULER_TOP) {
view->ruler_area.top = y;
y += view->ruler_area.height;
}
view->data_area.top = y;
y += view->data_area.height;
if (ruler == RULER_BOTTOM) {
view->ruler_area.top = y;
y += view->ruler_area.height;
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_update_bytes_per_line (mcview_t * view)
{
const screen_dimen cols = view->data_area.width;
int bytes;
if (cols < 8 + 17)
bytes = 4;
else
bytes = 4 * ((cols - 8) / ((cols < 80) ? 17 : 18));
assert (bytes != 0);
view->bytes_per_line = bytes;
view->dirty = mcview_max_dirt_limit + 1; /* To force refresh */
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_toggle_ruler (mcview_t * view)
{
static const enum ruler_type next[3] = {
RULER_TOP,
RULER_BOTTOM,
RULER_NONE
};
assert ((size_t) ruler < 3);
ruler = next[(size_t) ruler];
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_clean (mcview_t * view)
{
tty_setcolor (NORMAL_COLOR);
widget_erase ((Widget *) view);
if (view->dpy_frame_size != 0) {
tty_draw_box (view->widget.y, view->widget.x, view->widget.lines, view->widget.cols);
/* draw_double_box (view->widget.parent, view->widget.y,
view->widget.x, view->widget.lines, view->widget.cols);*/
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_ruler (mcview_t * view)
{
static const char ruler_chars[] = "|----*----";
const screen_dimen top = view->ruler_area.top;
const screen_dimen left = view->ruler_area.left;
const screen_dimen width = view->ruler_area.width;
const screen_dimen height = view->ruler_area.height;
const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
char r_buff[10];
off_t cl;
screen_dimen c;
if (ruler == RULER_NONE || height < 1)
return;
tty_setcolor (MARKED_COLOR);
for (c = 0; c < width; c++) {
cl = view->dpy_text_column + c;
if (line_row < height) {
widget_move (view, top + line_row, left + c);
tty_print_char (ruler_chars[cl % 10]);
}
if ((cl != 0) && (cl % 10) == 0) {
g_snprintf (r_buff, sizeof (r_buff), "%" OFFSETTYPE_PRId, (long unsigned int) cl);
if (nums_row < height) {
widget_move (view, top + nums_row, left + c - 1);
tty_print_string (r_buff);
}
}
}
tty_setcolor (NORMAL_COLOR);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_adjust_size (Dlg_head * h)
{
mcview_t *view;
WButtonBar *bar;
/* Look up the viewer and the buttonbar, we assume only two widgets here */
view = (mcview_t *) find_widget_type (h, mcview_callback);
bar = find_buttonbar (h);
widget_set_size (&view->widget, 0, 0, LINES - 1, COLS);
widget_set_size ((Widget *) bar, LINES - 1, 0, 1, COLS);
mcview_compute_areas (view);
mcview_update_bytes_per_line (view);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_percent (mcview_t * view, off_t p)
{
const screen_dimen top = view->status_area.top;
const screen_dimen right = view->status_area.left + view->status_area.width;
const screen_dimen height = view->status_area.height;
int percent;
off_t filesize;
if (height < 1 || right < 4)
return;
if (mcview_may_still_grow (view))
return;
filesize = mcview_get_filesize (view);
if (filesize == 0 || view->dpy_end == filesize)
percent = 100;
else if (p > (INT_MAX / 100))
percent = p / (filesize / 100);
else
percent = p * 100 / filesize;
widget_move (view, top, right - 4);
tty_printf ("%3d%%", percent);
}
/* --------------------------------------------------------------------------------------------- */

220
src/viewer/growbuf.c Normal file
View File

@ -0,0 +1,220 @@
/*
Internal file viewer for the Midnight Commander
Function for work with growing bufers
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 "../src/global.h"
#include "../src/wtools.h"
#include "internal.h"
/* Block size for reading files in parts */
#define VIEW_PAGE_SIZE ((size_t) 8192)
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_growbuf_init (mcview_t * view)
{
view->growbuf_in_use = TRUE;
view->growbuf_blockptr = NULL;
view->growbuf_blocks = 0;
view->growbuf_lastindex = VIEW_PAGE_SIZE;
view->growbuf_finished = FALSE;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_growbuf_free (mcview_t * view)
{
size_t i;
assert (view->growbuf_in_use);
for (i = 0; i < view->growbuf_blocks; i++)
g_free (view->growbuf_blockptr[i]);
g_free (view->growbuf_blockptr);
view->growbuf_blockptr = NULL;
view->growbuf_in_use = FALSE;
}
/* --------------------------------------------------------------------------------------------- */
off_t
mcview_growbuf_filesize (mcview_t * view)
{
assert (view->growbuf_in_use);
if (view->growbuf_blocks == 0)
return 0;
else
return ((off_t) view->growbuf_blocks - 1) * VIEW_PAGE_SIZE + view->growbuf_lastindex;
}
/* --------------------------------------------------------------------------------------------- */
/* Copies the output from the pipe to the growing buffer, until either
* the end-of-pipe is reached or the interval [0..ofs) of the growing
* buffer is completely filled. */
void
mcview_growbuf_read_until (mcview_t * view, off_t ofs)
{
ssize_t nread;
byte *p;
size_t bytesfree;
gboolean short_read;
assert (view->growbuf_in_use);
if (view->growbuf_finished)
return;
short_read = FALSE;
while (mcview_growbuf_filesize (view) < ofs || short_read) {
if (view->growbuf_lastindex == VIEW_PAGE_SIZE) {
/* Append a new block to the growing buffer */
byte *newblock = g_try_malloc (VIEW_PAGE_SIZE);
byte **newblocks = g_try_malloc (sizeof (*newblocks) * (view->growbuf_blocks + 1));
if (!newblock || !newblocks) {
g_free (newblock);
g_free (newblocks);
return;
}
memcpy (newblocks, view->growbuf_blockptr, sizeof (*newblocks) * view->growbuf_blocks);
g_free (view->growbuf_blockptr);
view->growbuf_blockptr = newblocks;
view->growbuf_blockptr[view->growbuf_blocks++] = newblock;
view->growbuf_lastindex = 0;
}
p = view->growbuf_blockptr[view->growbuf_blocks - 1] + view->growbuf_lastindex;
bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
if (view->datasource == DS_STDIO_PIPE) {
nread = fread (p, 1, bytesfree, view->ds_stdio_pipe);
if (nread == 0) {
view->growbuf_finished = TRUE;
(void) pclose (view->ds_stdio_pipe);
mcview_display (view);
close_error_pipe (D_NORMAL, NULL);
view->ds_stdio_pipe = NULL;
return;
}
} else {
assert (view->datasource == DS_VFS_PIPE);
do {
nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
} while (nread == -1 && errno == EINTR);
if (nread == -1 || nread == 0) {
view->growbuf_finished = TRUE;
(void) mc_close (view->ds_vfs_pipe);
view->ds_vfs_pipe = -1;
return;
}
}
short_read = ((size_t) nread < bytesfree);
view->growbuf_lastindex += nread;
}
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_get_byte_growing_buffer (mcview_t * view, off_t byte_index, int *retval)
{
if (retval)
*retval = -1;
off_t pageno = byte_index / VIEW_PAGE_SIZE;
off_t pageindex = byte_index % VIEW_PAGE_SIZE;
assert (view->growbuf_in_use);
if ((size_t) pageno != pageno)
return FALSE;
mcview_growbuf_read_until (view, byte_index + 1);
if (view->growbuf_blocks == 0)
return FALSE;
if (pageno < view->growbuf_blocks - 1) {
if (retval)
*retval = view->growbuf_blockptr[pageno][pageindex];
return TRUE;
}
if (pageno == view->growbuf_blocks - 1 && pageindex < view->growbuf_lastindex) {
if (retval)
*retval = view->growbuf_blockptr[pageno][pageindex];
return TRUE;
}
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
char *
mcview_get_ptr_growing_buffer (mcview_t * view, off_t byte_index)
{
off_t pageno = byte_index / VIEW_PAGE_SIZE;
off_t pageindex = byte_index % VIEW_PAGE_SIZE;
assert (view->growbuf_in_use);
if ((size_t) pageno != pageno)
return NULL;
mcview_growbuf_read_until (view, byte_index + 1);
if (view->growbuf_blocks == 0)
return NULL;
if (pageno < view->growbuf_blocks - 1)
return (char *) (view->growbuf_blockptr[pageno] + pageindex);
if (pageno == view->growbuf_blocks - 1 && pageindex < view->growbuf_lastindex)
return (char *) (view->growbuf_blockptr[pageno] + pageindex);
return NULL;
}
/* --------------------------------------------------------------------------------------------- */

346
src/viewer/hex.c Normal file
View File

@ -0,0 +1,346 @@
/*
Internal file viewer for the Midnight Commander
Function for hex view
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 "../src/global.h"
#include "../src/tty/tty.h"
#include "../src/tty/color.h"
#include "../src/main.h"
#include "../src/wtools.h"
#include "../src/charsets.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
typedef enum {
MARK_NORMAL,
MARK_SELECTED,
MARK_CURSOR,
MARK_CHANGED
} mark_t;
/*** file scope variables ************************************************************************/
static const char hex_char[] = "0123456789ABCDEF";
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_hex (mcview_t * view)
{
const screen_dimen top = view->data_area.top;
const screen_dimen left = view->data_area.left;
const screen_dimen height = view->data_area.height;
const screen_dimen width = view->data_area.width;
const int ngroups = view->bytes_per_line / 4;
const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (ngroups - 1 + 1));
/* 8 characters are used for the file offset, and every hex group
* takes 13 characters. On ``big'' screens, the groups are separated
* by an extra vertical line, and there is an extra space before the
* text column.
*/
screen_dimen row, col;
off_t from;
int c;
mark_t boldflag = MARK_NORMAL;
struct hexedit_change_node *curr = view->change_list;
size_t i;
int cw = 1;
int ch = 0;
gboolean read_res = TRUE;
char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
int bytes; /* Number of bytes already printed on the line */
mcview_display_clean (view);
/* Find the first displayable changed byte */
from = view->dpy_start;
while (curr && (curr->offset < from)) {
curr = curr->next;
}
for (row = 0; mcview_get_byte (view, from, NULL) == TRUE && row < height; row++) {
col = 0;
/* Print the hex offset */
g_snprintf (hex_buff, sizeof (hex_buff), "%08" OFFSETTYPE_PRIX " ",
(long unsigned int) from);
widget_move (view, top + row, left);
tty_setcolor (MARKED_COLOR);
for (i = 0; col < width && hex_buff[i] != '\0'; i++) {
tty_print_char (hex_buff[i]);
/* tty_print_char(hex_buff[i]);*/
col += 1;
}
tty_setcolor (NORMAL_COLOR);
for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++) {
#ifdef HAVE_CHARSET
if (view->utf8) {
ch = mcview_get_utf (view, from, &cw, &read_res);
if (!read_res)
break;
}
#endif
if (! mcview_get_byte (view, from, &c))
break;
/* Save the cursor position for mcview_place_cursor() */
if (from == view->hex_cursor && !view->hexview_in_text) {
view->cursor_row = row;
view->cursor_col = col;
}
/* Determine the state of the current byte */
boldflag =
(from == view->hex_cursor) ? MARK_CURSOR
: (curr != NULL && from == curr->offset) ? MARK_CHANGED
: (view->search_start <= from &&
from < view->search_end) ? MARK_SELECTED : MARK_NORMAL;
/* Determine the value of the current byte */
if (curr != NULL && from == curr->offset) {
c = curr->value;
curr = curr->next;
}
/* Select the color for the hex number */
tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
boldflag == MARK_SELECTED ? MARKED_COLOR :
boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
/* boldflag == MARK_CURSOR */
view->hexview_in_text ? MARKED_SELECTED_COLOR : VIEW_UNDERLINED_COLOR);
/* Print the hex number */
widget_move (view, top + row, left + col);
if (col < width) {
tty_print_char (hex_char[c / 16]);
col += 1;
}
if (col < width) {
tty_print_char (hex_char[c % 16]);
col += 1;
}
/* Print the separator */
tty_setcolor (NORMAL_COLOR);
if (bytes != view->bytes_per_line - 1) {
if (col < width) {
tty_print_char (' ');
col += 1;
}
/* After every four bytes, print a group separator */
if (bytes % 4 == 3) {
if (view->data_area.width >= 80 && col < width) {
tty_print_one_vline ();
col += 1;
}
if (col < width) {
tty_print_char (' ');
col += 1;
}
}
}
/* Select the color for the character; this differs from the
* hex color when boldflag == MARK_CURSOR */
tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
boldflag == MARK_SELECTED ? MARKED_COLOR :
boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
/* boldflag == MARK_CURSOR */
view->hexview_in_text ? VIEW_UNDERLINED_COLOR : MARKED_SELECTED_COLOR);
#ifdef HAVE_CHARSET
if (utf8_display) {
if (!view->utf8) {
ch = convert_from_8bit_to_utf_c ((unsigned char) ch, view->converter);
}
if (!g_unichar_isprint (ch))
ch = '.';
} else {
if (view->utf8) {
ch = convert_from_utf_to_current_c (ch, view->converter);
} else {
#endif
ch = convert_to_display_c (ch);
#ifdef HAVE_CHARSET
}
}
#endif
c = convert_to_display_c (c);
if (!g_ascii_isprint (c))
c = '.';
/* Print corresponding character on the text side */
if (text_start + bytes < width) {
widget_move (view, top + row, left + text_start + bytes);
if (!view->utf8) {
tty_print_char (c);
} else {
tty_print_anychar (ch);
}
}
/* Save the cursor position for mcview_place_cursor() */
if (from == view->hex_cursor && view->hexview_in_text) {
view->cursor_row = row;
view->cursor_col = text_start + bytes;
}
}
}
/* Be polite to the other functions */
tty_setcolor (NORMAL_COLOR);
mcview_place_cursor (view);
view->dpy_end = from;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_hexedit_save_changes (mcview_t * view)
{
struct hexedit_change_node *curr, *next;
int fp, answer;
char *text, *error;
if (view->change_list == NULL)
return TRUE;
retry_save:
assert (view->filename != NULL);
fp = mc_open (view->filename, O_WRONLY);
if (fp == -1)
goto save_error;
for (curr = view->change_list; curr != NULL; curr = next) {
next = curr->next;
if (mc_lseek (fp, curr->offset, SEEK_SET) == -1 || mc_write (fp, &(curr->value), 1) != 1)
goto save_error;
/* delete the saved item from the change list */
view->change_list = next;
view->dirty++;
mcview_set_byte (view, curr->offset, curr->value);
g_free (curr);
}
if (mc_close (fp) == -1) {
error = g_strdup (strerror (errno));
message (D_ERROR, _(" Save file "),
_(" Error while closing the file: \n %s \n"
" Data may have been written or not. "), error);
g_free (error);
}
mcview_update (view);
return TRUE;
save_error:
error = g_strdup (strerror (errno));
text = g_strdup_printf (_(" Cannot save file: \n %s "), error);
g_free (error);
(void) mc_close (fp);
answer = query_dialog (_(" Save file "), text, D_ERROR, 2, _("&Retry"), _("&Cancel"));
g_free (text);
if (answer == 0)
goto retry_save;
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_hexedit_mode (mcview_t * view)
{
view->hexedit_mode = !view->hexedit_mode;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_hexedit_free_change_list (mcview_t * view)
{
struct hexedit_change_node *curr, *next;
for (curr = view->change_list; curr != NULL; curr = next) {
next = curr->next;
g_free (curr);
}
view->change_list = NULL;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
{
/* chnode always either points to the head of the list or
* to one of the ->next fields in the list. The value at
* this location will be overwritten with the new node. */
struct hexedit_change_node **chnode = head;
while (*chnode != NULL && (*chnode)->offset < node->offset)
chnode = &((*chnode)->next);
node->next = *chnode;
*chnode = node;
}
/* --------------------------------------------------------------------------------------------- */

163
src/viewer/inlines.h Normal file
View File

@ -0,0 +1,163 @@
#ifndef MC_VIEWER_INLINES_H
#define MC_VIEWER_INLINES_H
/*** typedefs(not structures) and defined constants ********************/
/*** enums *************************************************************/
/*** structures declarations (and typedefs of structures)***************/
/*** global variables defined in .c file *******************************/
/*** declarations of public functions **********************************/
/*** inline functions ****************************************************************************/
static inline off_t
mcview_offset_doz (off_t a, off_t b)
{
return (a >= b) ? a - b : 0;
}
/* --------------------------------------------------------------------------------------------- */
static inline off_t
mcview_offset_rounddown (off_t a, off_t b)
{
assert (b != 0);
return a - a % b;
}
/* --------------------------------------------------------------------------------------------- */
/* difference or zero */
static inline screen_dimen
mcview_dimen_doz (screen_dimen a, screen_dimen b)
{
return (a >= b) ? a - b : 0;
}
/* --------------------------------------------------------------------------------------------- */
static inline screen_dimen
mcview_dimen_min (screen_dimen a, screen_dimen b)
{
return (a < b) ? a : b;
}
/* --------------------------------------------------------------------------------------------- */
/* {{{ Simple Primitive Functions for mcview_t }}} */
static inline gboolean
mcview_is_in_panel (mcview_t * view)
{
return (view->dpy_frame_size != 0);
}
/* --------------------------------------------------------------------------------------------- */
static inline gboolean
mcview_may_still_grow (mcview_t * view)
{
return (view->growbuf_in_use && !view->growbuf_finished);
}
/* --------------------------------------------------------------------------------------------- */
/* returns TRUE if the idx lies in the half-open interval
* [offset; offset + size), FALSE otherwise.
*/
static inline gboolean
mcview_already_loaded (off_t offset, off_t idx, size_t size)
{
return (offset <= idx && idx - offset < size);
}
/* --------------------------------------------------------------------------------------------- */
static inline gboolean
mcview_get_byte_file (mcview_t * view, off_t byte_index, int *retval)
{
assert (view->datasource == DS_FILE);
mcview_file_load_data (view, byte_index);
if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen)) {
if (retval)
*retval = view->ds_file_data[byte_index - view->ds_file_offset];
return TRUE;
}
if (retval)
*retval = -1;
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
static inline gboolean
mcview_get_byte (mcview_t * view, off_t offset, int *retval)
{
switch (view->datasource) {
case DS_STDIO_PIPE:
case DS_VFS_PIPE:
return mcview_get_byte_growing_buffer (view, offset, retval);
case DS_FILE:
return mcview_get_byte_file (view, offset, retval);
case DS_STRING:
return mcview_get_byte_string (view, offset, retval);
case DS_NONE:
return mcview_get_byte_none (view, offset, retval);
}
assert (!"Unknown datasource type");
return -1;
}
/* --------------------------------------------------------------------------------------------- */
static inline gboolean
mcview_get_byte_indexed (mcview_t * view, off_t base, off_t ofs, int *retval)
{
if (base <= OFFSETTYPE_MAX - ofs) {
return mcview_get_byte (view, base + ofs, retval);
}
if (retval)
*retval = -1;
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
static inline int
mcview_count_backspaces (mcview_t * view, off_t offset)
{
int backspaces = 0;
int c;
while (offset >= 2 * backspaces && mcview_get_byte (view, offset - 2 * backspaces, &c)
&& c == '\b')
backspaces++;
return backspaces;
}
/* --------------------------------------------------------------------------------------------- */
static inline gboolean
mcview_is_nroff_sequence (mcview_t * view, off_t offset)
{
int c0, c1, c2;
/* The following commands are ordered to speed up the calculation. */
if (! mcview_get_byte_indexed (view, offset, 1, &c1) || c1 != '\b')
return FALSE;
if (! mcview_get_byte_indexed (view, offset, 0, &c0) || !g_ascii_isprint (c0))
return FALSE;
if (! mcview_get_byte_indexed (view, offset, 2, &c2) || !g_ascii_isprint (c2))
return FALSE;
return (c0 == c2 || c0 == '_' || (c0 == '+' && c2 == 'o'));
}
/* --------------------------------------------------------------------------------------------- */
#endif

318
src/viewer/internal.h Normal file
View File

@ -0,0 +1,318 @@
#ifndef MC_VIEWER_INTERNAL_H
#define MC_VIEWER_INTERNAL_H
#include <stdlib.h>
#include <sys/types.h>
#include "../src/global.h"
#include "../src/widget.h"
#include "../src/search/search.h"
/*** typedefs(not structures) and defined constants ********************/
typedef unsigned char byte;
/* A width or height on the screen */
typedef unsigned int screen_dimen;
#define OFFSETTYPE_PRIX "lX"
#define OFFSETTYPE_PRId "lu"
extern const off_t INVALID_OFFSET;
extern const off_t OFFSETTYPE_MAX;
/*** enums *************************************************************/
/* data sources of the view */
enum view_ds {
DS_NONE, /* No data available */
DS_STDIO_PIPE, /* Data comes from a pipe using popen/pclose */
DS_VFS_PIPE, /* Data comes from a piped-in VFS file */
DS_FILE, /* Data comes from a VFS file */
DS_STRING /* Data comes from a string in memory */
};
enum ccache_type {
CCACHE_OFFSET,
CCACHE_LINECOL
};
typedef enum {
NROFF_TYPE_NONE = 0,
NROFF_TYPE_BOLD = 1,
NROFF_TYPE_UNDERLINE = 2
} nroff_type_t;
/*** structures declarations (and typedefs of structures)***************/
/* A node for building a change list on change_list */
struct hexedit_change_node {
struct hexedit_change_node *next;
off_t offset;
byte value;
};
struct area {
screen_dimen top, left;
screen_dimen height, width;
};
/* A cache entry for mapping offsets into line/column pairs and vice versa.
* cc_offset, cc_line, and cc_column are the 0-based values of the offset,
* line and column of that cache entry. cc_nroff_column is the column
* corresponding to cc_offset in nroff mode.
*/
struct coord_cache_entry {
off_t cc_offset;
off_t cc_line;
off_t cc_column;
off_t cc_nroff_column;
};
struct mcview_nroff_struct;
typedef struct mcview_struct {
Widget widget;
char *filename; /* Name of the file */
char *command; /* Command used to pipe data in */
enum view_ds datasource; /* Where the displayed data comes from */
/* stdio pipe data source */
FILE *ds_stdio_pipe; /* Output of a shell command */
/* vfs pipe data source */
int ds_vfs_pipe; /* Non-seekable vfs file descriptor */
/* vfs file data source */
int ds_file_fd; /* File with random access */
off_t ds_file_filesize; /* Size of the file */
off_t ds_file_offset; /* Offset of the currently loaded data */
byte *ds_file_data; /* Currently loaded data */
size_t ds_file_datalen; /* Number of valid bytes in file_data */
size_t ds_file_datasize; /* Number of allocated bytes in file_data */
/* string data source */
byte *ds_string_data; /* The characters of the string */
size_t ds_string_len; /* The length of the string */
/* Growing buffers information */
gboolean growbuf_in_use; /* Use the growing buffers? */
byte **growbuf_blockptr; /* Pointer to the block pointers */
size_t growbuf_blocks; /* The number of blocks in *block_ptr */
size_t growbuf_lastindex; /* Number of bytes in the last page of the
growing buffer */
gboolean growbuf_finished; /* TRUE when all data has been read. */
/* Editor modes */
gboolean hex_mode; /* Hexview or Hexedit */
gboolean hexedit_mode; /* Hexedit */
gboolean hexview_in_text; /* Is the hexview cursor in the text area? */
gboolean text_nroff_mode; /* Nroff-style highlighting */
gboolean text_wrap_mode; /* Wrap text lines to fit them on the screen */
gboolean magic_mode; /* Preprocess the file using external programs */
gboolean utf8; /* It's multibyte file codeset */
/* Additional editor state */
gboolean hexedit_lownibble; /* Are we editing the last significant nibble? */
GArray *coord_cache; /* Cache for mapping offsets to cursor positions */
/* Display information */
screen_dimen dpy_frame_size; /* Size of the frame surrounding the real viewer */
off_t dpy_start; /* Offset of the displayed data */
off_t dpy_end; /* Offset after the displayed data */
off_t dpy_text_column; /* Number of skipped columns in non-wrap
* text mode */
off_t hex_cursor; /* Hexview cursor position in file */
screen_dimen cursor_col; /* Cursor column */
screen_dimen cursor_row; /* Cursor row */
struct hexedit_change_node *change_list; /* Linked list of changes */
struct area status_area; /* Where the status line is displayed */
struct area ruler_area; /* Where the ruler is displayed */
struct area data_area; /* Where the data is displayed */
int dirty; /* Number of skipped updates */
gboolean dpy_bbar_dirty; /* Does the button bar need to be updated? */
/* Mode variables */
int bytes_per_line; /* Number of bytes per line in hex mode */
/* Search variables */
off_t search_start; /* First character to start searching from */
off_t search_end; /* Length of found string or 0 if none was found */
/* Pointer to the last search command */
gboolean want_to_quit; /* Prepare for cleanup ... */
/* Markers */
int marker; /* mark to use */
off_t marks[10]; /* 10 marks: 0..9 */
int move_dir; /* return value from widget:
* 0 do nothing
* -1 view previous file
* 1 view next file
*/
off_t update_steps; /* The number of bytes between percent
* increments */
off_t update_activate; /* Last point where we updated the status */
/* converter for translation of text */
GIConv converter;
/* handle of search engine */
mc_search_t *search;
gchar *last_search_string;
mc_search_type_t search_type;
gboolean search_all_codepages;
gboolean whole_words;
gboolean search_case;
gboolean search_backwards;
struct mcview_nroff_struct *search_nroff_seq;
int search_numNeedSkipChar;
} mcview_t;
typedef struct mcview_nroff_struct {
mcview_t *view;
off_t index;
int char_width;
int current_char;
nroff_type_t type;
nroff_type_t prev_type;
} mcview_nroff_t;
/*** global variables defined in .c file *******************************/
/*** declarations of public functions **********************************/
/* actions_cmd.c: callbacks */
cb_ret_t mcview_callback (Widget *, widget_msg_t, int);
cb_ret_t mcview_dialog_callback (Dlg_head *, dlg_msg_t, int);
void mcview_help_cmd (void);
void mcview_quit_cmd (mcview_t *);
void mcview_toggle_hex_mode_cmd (mcview_t *);
void mcview_moveto_line_cmd (mcview_t *);
void mcview_moveto_addr_cmd (mcview_t *);
void mcview_toggle_hexedit_mode_cmd (mcview_t *);
void mcview_hexedit_save_changes_cmd (mcview_t *);
void mcview_toggle_wrap_mode_cmd (mcview_t *);
void mcview_search_cmd (mcview_t *);
void mcview_toggle_magic_mode_cmd (mcview_t *);
void mcview_toggle_nroff_mode_cmd (mcview_t *);
void mcview_toggle_ruler_cmd (mcview_t *);
/* coord_cache.c: */
gboolean mcview_coord_cache_entry_less (const struct coord_cache_entry *,
const struct coord_cache_entry *, enum ccache_type,
gboolean);
#ifdef MC_ENABLE_DEBUGGING_CODE
void mcview_ccache_dump (mcview_t *);
#endif
void
mcview_ccache_lookup (mcview_t *, struct coord_cache_entry *, enum ccache_type);
/* datasource.c: */
void mcview_set_datasource_none (mcview_t *);
off_t mcview_get_filesize (mcview_t *);
char *mcview_get_ptr_file (mcview_t *, off_t);
char *mcview_get_ptr_string (mcview_t *, off_t);
int mcview_get_utf (mcview_t *, off_t, int *, gboolean *);
gboolean mcview_get_byte_string (mcview_t *, off_t, int *);
gboolean mcview_get_byte_none (mcview_t *, off_t, int *);
void mcview_set_byte (mcview_t *, off_t, byte);
void mcview_file_load_data (mcview_t *, off_t);
void mcview_close_datasource (mcview_t *);
void mcview_set_datasource_file (mcview_t *, int, const struct stat *);
gboolean mcview_load_command_output (mcview_t *, const char *);
void mcview_set_datasource_vfs_pipe (mcview_t *, int);
void mcview_set_datasource_string (mcview_t *, const char *);
/* dialog.c: */
gboolean mcview_dialog_search (mcview_t *);
/* display.c: */
void mcview_update (mcview_t *);
void mcview_display (mcview_t *);
void mcview_compute_areas (mcview_t *);
void mcview_update_bytes_per_line (mcview_t *);
void mcview_display_toggle_ruler (mcview_t *);
void mcview_display_clean (mcview_t *);
void mcview_display_ruler (mcview_t *);
void mcview_adjust_size (Dlg_head *);
void mcview_percent (mcview_t *, off_t);
/* growbuf.c: */
void mcview_growbuf_init (mcview_t *);
void mcview_growbuf_free (mcview_t *);
off_t mcview_growbuf_filesize (mcview_t *);
void mcview_growbuf_read_until (mcview_t *, off_t);
gboolean mcview_get_byte_growing_buffer (mcview_t *, off_t, int *);
char *mcview_get_ptr_growing_buffer (mcview_t *, off_t);
/* hex.c: */
void mcview_display_hex (mcview_t *);
gboolean mcview_hexedit_save_changes (mcview_t *);
void mcview_toggle_hexedit_mode (mcview_t *);
void mcview_hexedit_free_change_list (mcview_t *);
void mcview_enqueue_change (struct hexedit_change_node **, struct hexedit_change_node *);
/* lib.c: */
void mcview_toggle_magic_mode (mcview_t *);
void mcview_toggle_wrap_mode (mcview_t *);
void mcview_toggle_nroff_mode (mcview_t *);
void mcview_toggle_hex_mode (mcview_t *);
gboolean mcview_ok_to_quit (mcview_t *);
void mcview_done (mcview_t *);
void mcview_select_encoding (mcview_t *);
void mcview_show_error (mcview_t *, const char *);
/* move.c */
void mcview_move_up (mcview_t *, off_t);
void mcview_move_down (mcview_t *, off_t);
void mcview_move_left (mcview_t *, off_t);
void mcview_move_right (mcview_t *, off_t);
void mcview_scroll_to_cursor (mcview_t *);
void mcview_moveto_top (mcview_t *);
void mcview_moveto_bottom (mcview_t *);
void mcview_moveto_bol (mcview_t *);
void mcview_moveto_eol (mcview_t *);
void mcview_moveto_offset (mcview_t *, off_t);
void mcview_moveto (mcview_t *, off_t, off_t);
void mcview_coord_to_offset (mcview_t *, off_t *, off_t, off_t);
void mcview_offset_to_coord (mcview_t *, off_t *, off_t *, off_t);
void mcview_place_cursor (mcview_t *);
void mcview_moveto_match (mcview_t *);
/* nroff.c: */
void mcview_display_nroff (mcview_t *);
int mcview__get_nroff_real_len (mcview_t *, off_t, off_t);
mcview_nroff_t *mcview_nroff_seq_new_num (mcview_t * view, off_t);
mcview_nroff_t *mcview_nroff_seq_new (mcview_t * view);
void mcview_nroff_seq_free (mcview_nroff_t **);
nroff_type_t mcview_nroff_seq_info (mcview_nroff_t *);
int mcview_nroff_seq_next (mcview_nroff_t *);
/* plain.c: */
void mcview_display_text (mcview_t *);
/* search.c: */
int mcview_search_cmd_callback (const void *user_data, gsize char_offset);
int mcview_search_update_cmd_callback (const void *, gsize);
void mcview_do_search (mcview_t *);
/*** inline functions ****************************************************************************/
#include "inlines.h"
#endif

247
src/viewer/lib.c Normal file
View File

@ -0,0 +1,247 @@
/*
Internal file viewer for the Midnight Commander
Common finctions (used from some other mcviewer 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 <limits.h>
#include "../src/global.h"
#include "../src/wtools.h"
#include "../src/strutil.h"
#include "../src/main.h"
#include "../src/charsets.h"
#include "../src/selcodepage.h"
#include "internal.h"
#include "mcviewer.h"
/*** global variables ****************************************************************************/
#define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
const off_t INVALID_OFFSET = (off_t) -1;
const off_t OFFSETTYPE_MAX = ((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1;
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_magic_mode (mcview_t * view)
{
char *filename, *command;
mcview_altered_magic_flag = 1;
view->magic_mode = !view->magic_mode;
filename = g_strdup (view->filename);
command = g_strdup (view->command);
mcview_done (view);
mcview_load (view, command, filename, 0);
g_free (filename);
g_free (command);
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_wrap_mode (mcview_t * view)
{
view->text_wrap_mode = !view->text_wrap_mode;
if (view->text_wrap_mode) {
mcview_scroll_to_cursor (view);
} else {
off_t line;
mcview_offset_to_coord (view, &line, &(view->dpy_text_column), view->dpy_start);
mcview_coord_to_offset (view, &(view->dpy_start), line, 0);
}
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_nroff_mode (mcview_t * view)
{
view->text_nroff_mode = !view->text_nroff_mode;
mcview_altered_nroff_flag = 1;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_hex_mode (mcview_t * view)
{
view->hex_mode = !view->hex_mode;
if (view->hex_mode) {
view->hex_cursor = view->dpy_start;
view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
view->widget.options |= W_WANT_CURSOR;
} else {
view->dpy_start = view->hex_cursor;
mcview_moveto_bol (view);
view->widget.options &= ~W_WANT_CURSOR;
}
mcview_altered_hex_mode = 1;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_ok_to_quit (mcview_t * view)
{
int r;
if (view->change_list == NULL)
return TRUE;
r = query_dialog (_("Quit"),
_(" File was modified, Save with exit? "), D_NORMAL, 3,
_("&Cancel quit"), _("&Yes"), _("&No"));
switch (r) {
case 1:
return mcview_hexedit_save_changes (view);
case 2:
mcview_hexedit_free_change_list (view);
return TRUE;
default:
return FALSE;
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_done (mcview_t * view)
{
/* Save current file position */
if (mcview_remember_file_position && view->filename != NULL) {
char *canon_fname;
off_t line, col;
canon_fname = vfs_canon (view->filename);
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
save_file_position (canon_fname, line + 1, col);
g_free (canon_fname);
}
/* Write back the global viewer mode */
mcview_default_hex_mode = view->hex_mode;
mcview_default_nroff_flag = view->text_nroff_mode;
mcview_default_magic_flag = view->magic_mode;
mcview_global_wrap_mode = view->text_wrap_mode;
/* Free memory used by the viewer */
/* view->widget needs no destructor */
g_free (view->filename), view->filename = NULL;
g_free (view->command), view->command = NULL;
mcview_close_datasource (view);
/* the growing buffer is freed with the datasource */
if (view->coord_cache) {
g_array_free (view->coord_cache, TRUE), view->coord_cache = NULL;
}
mcview_hexedit_free_change_list (view);
/* FIXME: what about view->search_exp? */
if (view->converter != str_cnv_from_term)
str_close_conv (view->converter);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_select_encoding (mcview_t * view)
{
#ifdef HAVE_CHARSET
const char *cp_id = NULL;
if (do_select_codepage ()) {
cp_id = get_codepage_id (source_codepage >= 0 ?
source_codepage : display_codepage);
if (cp_id != NULL) {
GIConv conv;
conv = str_crt_conv_from (cp_id);
if (conv != INVALID_CONV) {
if (view->converter != str_cnv_from_term)
str_close_conv (view->converter);
view->converter = conv;
}
}
if (cp_id != NULL)
view->utf8 = (gboolean) str_isutf8 (cp_id);
}
#endif
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_show_error (mcview_t * view, const char *msg)
{
mcview_close_datasource (view);
if (mcview_is_in_panel (view)) {
mcview_set_datasource_string (view, msg);
} else {
message (D_ERROR, MSG_ERROR, "%s", msg);
}
}
/* --------------------------------------------------------------------------------------------- */

403
src/viewer/mcviewer.c Normal file
View File

@ -0,0 +1,403 @@
/*
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 "../src/global.h"
#include "../src/strutil.h"
#include "../src/main.h"
#include "../src/charsets.h"
#include "../src/tty/tty.h"
#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;
/*** 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;
/* 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;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
mcview_t *
mcview_new (int y, int x, int cols, int lines, int is_panel)
{
mcview_t *view = g_new0 (mcview_t, 1);
size_t i;
init_widget (&view->widget, y, x, lines, cols, mcview_callback, mcview_real_event);
view->filename = NULL;
view->command = NULL;
view->search_nroff_seq = NULL;
mcview_set_datasource_none (view);
view->growbuf_in_use = FALSE;
/* leave the other growbuf fields uninitialized */
view->hex_mode = FALSE;
view->hexedit_mode = FALSE;
view->hexview_in_text = FALSE;
view->text_nroff_mode = FALSE;
view->text_wrap_mode = FALSE;
view->magic_mode = FALSE;
view->utf8 = FALSE;
view->hexedit_lownibble = FALSE;
view->coord_cache = NULL;
view->dpy_frame_size = is_panel ? 1 : 0;
view->dpy_start = 0;
view->dpy_text_column = 0;
view->dpy_end = 0;
view->hex_cursor = 0;
view->cursor_col = 0;
view->cursor_row = 0;
view->change_list = NULL;
view->converter = str_cnv_from_term;
/* {status,ruler,data}_area are left uninitialized */
view->dirty = 0;
view->dpy_bbar_dirty = TRUE;
view->bytes_per_line = 1;
view->search_start = 0;
view->search_end = 0;
view->want_to_quit = FALSE;
view->marker = 0;
for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
view->marks[i] = 0;
view->move_dir = 0;
view->update_steps = 0;
view->update_activate = 0;
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 */
int
mcview_viewer (const char *command, const char *file, int *move_dir_p, int start_line)
{
gboolean succeeded;
mcview_t *mcview_t;
WButtonBar *bar;
Dlg_head *view_dlg;
/* Create dialog and widgets, put them on the dialog */
view_dlg =
create_dlg (0, 0, LINES, COLS, NULL, mcview_dialog_callback,
"[Internal File Viewer]", NULL, DLG_WANT_TAB);
mcview_t = mcview_new (0, 0, COLS, LINES - 1, 0);
bar = buttonbar_new (1);
add_widget (view_dlg, bar);
add_widget (view_dlg, mcview_t);
succeeded = mcview_load (mcview_t, command, file, start_line);
if (succeeded) {
run_dlg (view_dlg);
if (move_dir_p)
*move_dir_p = mcview_t->move_dir;
} else {
if (move_dir_p)
*move_dir_p = 0;
}
destroy_dlg (view_dlg);
return succeeded;
}
/* {{{ Miscellaneous functions }}} */
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_load (mcview_t * view, const char *command, const char *file, int start_line)
{
int i, type;
int fd = -1;
char tmp[BUF_MEDIUM];
const char *enc;
char *canon_fname;
struct stat st;
#ifdef HAVE_CHARSET
const char *cp_id = NULL;
#endif
gboolean retval = FALSE;
#ifdef HAVE_CHARSET
cp_id = get_codepage_id (source_codepage);
if (cp_id != NULL && str_isutf8 (cp_id) != 0)
view->utf8 = TRUE;
else
view->utf8 = FALSE;
#endif
assert (view->bytes_per_line != 0);
mcview_done (view);
/* Set up the state */
mcview_set_datasource_none (view);
view->filename = g_strdup (file);
view->command = 0;
/* Clear the markers */
view->marker = 0;
for (i = 0; i < 10; i++)
view->marks[i] = 0;
if (!mcview_is_in_panel (view)) {
view->dpy_text_column = 0;
}
if (command && (view->magic_mode || file == NULL || file[0] == '\0')) {
retval = mcview_load_command_output (view, command);
} else if (file != NULL && file[0] != '\0') {
/* Open the file */
if ((fd = mc_open (file, O_RDONLY | O_NONBLOCK)) == -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;
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;
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;
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 {
type = get_compression_type (fd);
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;
view->converter = str_cnv_from_term;
#ifdef HAVE_CHARSET
cp_id = get_codepage_id (source_codepage >= 0 ?
source_codepage : display_codepage);
if (cp_id != NULL) {
GIConv conv;
conv = str_crt_conv_from (cp_id);
if (conv != INVALID_CONV) {
if (view->converter != str_cnv_from_term)
str_close_conv (view->converter);
view->converter = conv;
}
}
if (cp_id != NULL)
view->utf8 = (gboolean) str_isutf8 (cp_id);
#endif
mcview_compute_areas (view);
assert (view->bytes_per_line != 0);
if (mcview_remember_file_position && view->filename != NULL && start_line == 0) {
long line, col;
canon_fname = vfs_canon (view->filename);
load_file_position (canon_fname, &line, &col);
g_free (canon_fname);
mcview_moveto (view, mcview_offset_doz (line, 1), col);
} 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;
}
/* --------------------------------------------------------------------------------------------- */

50
src/viewer/mcviewer.h Normal file
View File

@ -0,0 +1,50 @@
/** \file view.h
* \brief Header: internal file viewer
*/
#ifndef MC_VIEWER_H
#define MC_VIEWER_H
/*** typedefs(not structures) and defined constants ********************/
struct mcview_struct;
/*** enums *************************************************************/
/*** structures declarations (and typedefs of structures)***************/
/*** global variables defined in .c file *******************************/
extern int mcview_default_hex_mode;
extern int mcview_default_nroff_flag;
extern int mcview_global_wrap_mode;
extern int mcview_default_magic_flag;
extern int mcview_altered_hex_mode;
extern int mcview_altered_magic_flag;
extern int mcview_altered_nroff_flag;
extern int mcview_remember_file_position;
extern int mcview_max_dirt_limit;
extern int mcview_mouse_move_pages;
/*** declarations of public functions **********************************/
/* Creates a new mcview_t object with the given properties. Caveat: the
* origin is in y-x order, while the extent is in x-y order. */
extern struct mcview_struct *mcview_new (int, int, int, int, int);
/* Shows {file} or the output of {command} in the internal viewer,
* starting in line {start_line}. {ret_move_direction} may be NULL or
* point to a variable that will receive the direction in which the user
* wants to move (-1 = previous file, 1 = next file, 0 = do nothing).
*/
extern int mcview_viewer (const char *command, const char *file,
int *ret_move_direction, int start_line);
extern gboolean mcview_load (struct mcview_struct *, const char *, const char *, int);
#endif

442
src/viewer/move.c Normal file
View File

@ -0,0 +1,442 @@
/*
Internal file viewer for the Midnight Commander
Functions for handle cursor movement
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.
*/
/*
The following variables have to do with the current position and are
updated by the cursor movement functions.
In hex view and wrapped text view mode, dpy_start marks the offset of
the top-left corner on the screen, in non-wrapping text mode it is
the beginning of the current line. In hex mode, hex_cursor is the
offset of the cursor. In non-wrapping text mode, dpy_text_column is
the number of columns that are hidden on the left side on the screen.
In hex mode, dpy_start is updated by the view_fix_cursor_position()
function in order to keep the other functions simple. In
non-wrapping text mode dpy_start and dpy_text_column are normalized
such that dpy_text_column < view_get_datacolumns().
*/
#include <config.h>
#include "../src/global.h"
#include "../src/tty/tty.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
static void
mcview_movement_fixups (mcview_t * view, gboolean reset_search)
{
mcview_scroll_to_cursor (view);
if (reset_search) {
view->search_start = view->dpy_start;
view->search_end = view->dpy_start;
}
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_up (mcview_t * view, off_t lines)
{
if (view->hex_mode) {
off_t bytes = lines * view->bytes_per_line;
if (view->hex_cursor >= bytes) {
view->hex_cursor -= bytes;
if (view->hex_cursor < view->dpy_start)
view->dpy_start = mcview_offset_doz (view->dpy_start, bytes);
} else {
view->hex_cursor %= view->bytes_per_line;
}
} else if (view->text_wrap_mode) {
const screen_dimen width = view->data_area.width;
off_t i, col, line, linestart;
for (i = 0; i < lines; i++) {
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
if (col >= width) {
col -= width;
} else if (line >= 1) {
mcview_coord_to_offset (view, &linestart, line, 0);
mcview_offset_to_coord (view, &line, &col, linestart - 1);
/* if the only thing that would be displayed were a
* single newline character, advance to the previous
* part of the line. */
if (col > 0 && col % width == 0)
col -= width;
else
col -= col % width;
} else {
/* nothing to do */
}
mcview_coord_to_offset (view, &(view->dpy_start), line, col);
}
} else {
off_t line, column;
mcview_offset_to_coord (view, &line, &column, view->dpy_start);
line = mcview_offset_doz (line, lines);
mcview_coord_to_offset (view, &(view->dpy_start), line, column);
}
mcview_movement_fixups (view, (lines != 1));
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_down (mcview_t * view, off_t lines)
{
if (view->hex_mode) {
off_t i, limit, last_byte;
last_byte = mcview_get_filesize (view);
if (last_byte >= (off_t) view->bytes_per_line)
limit = last_byte - view->bytes_per_line;
else
limit = 0;
for (i = 0; i < lines && view->hex_cursor < limit; i++) {
view->hex_cursor += view->bytes_per_line;
if (lines != 1)
view->dpy_start += view->bytes_per_line;
}
} else if (view->dpy_end == mcview_get_filesize (view)) {
/* don't move further down. There's nothing more to see. */
} else if (view->text_wrap_mode) {
off_t line, col, i;
int c;
for (i = 0; i < lines; i++) {
off_t new_offset, chk_line, chk_col;
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
col += view->data_area.width;
mcview_coord_to_offset (view, &new_offset, line, col);
/* skip to the next line if the only thing that would be
* displayed is the newline character. */
mcview_offset_to_coord (view, &chk_line, &chk_col, new_offset);
if (chk_line == line && chk_col == col && mcview_get_byte (view, new_offset, &c) == TRUE
&& c == '\n')
new_offset++;
view->dpy_start = new_offset;
}
} else {
off_t line, col;
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
line += lines;
mcview_coord_to_offset (view, &(view->dpy_start), line, col);
}
mcview_movement_fixups (view, (lines != 1));
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_left (mcview_t * view, off_t columns)
{
if (view->hex_mode) {
assert (columns == 1);
if (view->hexview_in_text || !view->hexedit_lownibble) {
if (view->hex_cursor > 0)
view->hex_cursor--;
}
if (!view->hexview_in_text)
view->hexedit_lownibble = !view->hexedit_lownibble;
} else if (view->text_wrap_mode) {
/* nothing to do */
} else {
if (view->dpy_text_column >= columns)
view->dpy_text_column -= columns;
else
view->dpy_text_column = 0;
}
mcview_movement_fixups (view, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_move_right (mcview_t * view, off_t columns)
{
if (view->hex_mode) {
assert (columns == 1);
if (view->hexview_in_text || view->hexedit_lownibble) {
view->hex_cursor++;
}
if (!view->hexview_in_text)
view->hexedit_lownibble = !view->hexedit_lownibble;
} else if (view->text_wrap_mode) {
/* nothing to do */
} else {
view->dpy_text_column += columns;
}
mcview_movement_fixups (view, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_scroll_to_cursor (mcview_t * view)
{
if (view->hex_mode) {
const off_t bytes = view->bytes_per_line;
const off_t displaysize = view->data_area.height * bytes;
const off_t cursor = view->hex_cursor;
off_t topleft = view->dpy_start;
if (topleft + displaysize <= cursor)
topleft = mcview_offset_rounddown (cursor, bytes)
- (displaysize - bytes);
if (cursor < topleft)
topleft = mcview_offset_rounddown (cursor, bytes);
view->dpy_start = topleft;
} else if (view->text_wrap_mode) {
off_t line, col, columns;
columns = view->data_area.width;
mcview_offset_to_coord (view, &line, &col, view->dpy_start + view->dpy_text_column);
if (columns != 0)
col = mcview_offset_rounddown (col, columns);
mcview_coord_to_offset (view, &(view->dpy_start), line, col);
view->dpy_text_column = 0;
} else {
/* nothing to do */
}
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_top (mcview_t * view)
{
view->dpy_start = 0;
view->hex_cursor = 0;
view->dpy_text_column = 0;
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_bottom (mcview_t * view)
{
off_t datalines, lines_up, filesize, last_offset;
if (view->growbuf_in_use)
mcview_growbuf_read_until (view, OFFSETTYPE_MAX);
filesize = mcview_get_filesize (view);
last_offset = mcview_offset_doz (filesize, 1);
datalines = view->data_area.height;
lines_up = mcview_offset_doz (datalines, 1);
if (view->hex_mode) {
view->hex_cursor = filesize;
mcview_move_up (view, lines_up);
view->hex_cursor = last_offset;
} else {
view->dpy_start = last_offset;
mcview_moveto_bol (view);
mcview_move_up (view, lines_up);
}
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_bol (mcview_t * view)
{
if (view->hex_mode) {
view->hex_cursor -= view->hex_cursor % view->bytes_per_line;
} else if (view->text_wrap_mode) {
/* do nothing */
} else {
off_t line, column;
mcview_offset_to_coord (view, &line, &column, view->dpy_start);
mcview_coord_to_offset (view, &(view->dpy_start), line, 0);
view->dpy_text_column = 0;
}
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_eol (mcview_t * view)
{
if (view->hex_mode) {
off_t filesize, bol;
bol = mcview_offset_rounddown (view->hex_cursor, view->bytes_per_line);
if (mcview_get_byte_indexed (view, bol, view->bytes_per_line - 1, NULL) == TRUE) {
view->hex_cursor = bol + view->bytes_per_line - 1;
} else {
filesize = mcview_get_filesize (view);
view->hex_cursor = mcview_offset_doz (filesize, 1);
}
} else if (view->text_wrap_mode) {
/* nothing to do */
} else {
off_t line, col;
mcview_offset_to_coord (view, &line, &col, view->dpy_start);
mcview_coord_to_offset (view, &(view->dpy_start), line, OFFSETTYPE_MAX);
}
mcview_movement_fixups (view, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto_offset (mcview_t * view, off_t offset)
{
if (view->hex_mode) {
view->hex_cursor = offset;
view->dpy_start = offset - offset % view->bytes_per_line;
} else {
view->dpy_start = offset;
}
mcview_movement_fixups (view, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_moveto (mcview_t * view, off_t line, off_t col)
{
off_t offset;
mcview_coord_to_offset (view, &offset, line, col);
mcview_moveto_offset (view, offset);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_coord_to_offset (mcview_t * view, off_t * ret_offset, off_t line, off_t column)
{
struct coord_cache_entry coord;
coord.cc_line = line;
coord.cc_column = column;
coord.cc_nroff_column = column;
mcview_ccache_lookup (view, &coord, CCACHE_OFFSET);
*ret_offset = coord.cc_offset;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_offset_to_coord (mcview_t * view, off_t * ret_line, off_t * ret_column, off_t offset)
{
struct coord_cache_entry coord;
coord.cc_offset = offset;
mcview_ccache_lookup (view, &coord, CCACHE_LINECOL);
if (ret_line)
*ret_line = coord.cc_line;
if (ret_column)
*ret_column = (view->text_nroff_mode)
? coord.cc_nroff_column : coord.cc_column;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_place_cursor (mcview_t * view)
{
const screen_dimen top = view->data_area.top;
const screen_dimen left = view->data_area.left;
screen_dimen col;
col = view->cursor_col;
if (!view->hexview_in_text && view->hexedit_lownibble)
col++;
widget_move (&view->widget, top + view->cursor_row, left + col);
}
/* --------------------------------------------------------------------------------------------- */
/* we have set view->search_start and view->search_end and must set
* view->dpy_text_column and view->dpy_start
* try to display maximum of match */
void
mcview_moveto_match (mcview_t * view)
{
off_t search_line, search_col, offset;
mcview_offset_to_coord (view, &search_line, &search_col, view->search_start);
if (!view->hex_mode)
search_col = 0;
mcview_coord_to_offset (view, &offset, search_line, search_col);
if (view->hex_mode) {
view->hex_cursor = offset;
view->dpy_start = offset - offset % view->bytes_per_line;
} else {
view->dpy_start = offset;
}
mcview_scroll_to_cursor (view);
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */

308
src/viewer/nroff.c Normal file
View File

@ -0,0 +1,308 @@
/*
Internal file viewer for the Midnight Commander
Function for nroff-like view
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 "../src/global.h"
#include "../src/main.h"
#include "../src/charsets.h"
#include "../src/tty/tty.h"
#include "../src/tty/color.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_nroff (mcview_t * view)
{
const screen_dimen left = view->data_area.left;
const screen_dimen top = view->data_area.top;
const screen_dimen width = view->data_area.width;
const screen_dimen height = view->data_area.height;
screen_dimen row, col;
off_t from;
int cw = 1;
int c;
int c_prev = 0;
int c_next = 0;
gboolean read_res = TRUE;
struct hexedit_change_node *curr = view->change_list;
mcview_display_clean (view);
mcview_display_ruler (view);
/* Find the first displayable changed byte */
from = view->dpy_start;
while (curr && (curr->offset < from)) {
curr = curr->next;
}
tty_setcolor (NORMAL_COLOR);
for (row = 0, col = 0; row < height;) {
#ifdef HAVE_CHARSET
if (view->utf8) {
c = mcview_get_utf (view, from, &cw, &read_res);
if (!read_res)
break;
} else
#endif
{
if (! mcview_get_byte (view, from, &c))
break;
}
from++;
if (cw > 1)
from += cw - 1;
if (c == '\b') {
if (from > 1) {
mcview_get_byte (view, from - 2, &c_prev);
mcview_get_byte (view, from, &c_next);
}
if (g_ascii_isprint (c_prev) && g_ascii_isprint (c_prev)
&& (c_prev == c_next || c_prev == '_' || (c_prev == '+' && c_next == 'o'))) {
if (col == 0) {
if (row == 0) {
/* We're inside an nroff character sequence at the
* beginning of the screen -- just skip the
* backspace and continue with the next character. */
continue;
}
row--;
col = width;
}
col--;
if (c_prev == '_'
&& (c_next != '_' || mcview_count_backspaces (view, from + 1) == 1))
tty_setcolor (VIEW_UNDERLINED_COLOR);
else
tty_setcolor (MARKED_COLOR);
continue;
}
}
if ((c == '\n') || (col >= width && view->text_wrap_mode)) {
col = 0;
row++;
if (c == '\n' || row >= height)
continue;
}
if (c == '\r') {
mcview_get_byte_indexed (view, from, 1, &c);
if (c == '\r' || c == '\n')
continue;
col = 0;
row++;
continue;
}
if (c == '\t') {
off_t line, column;
mcview_offset_to_coord (view, &line, &column, from);
col += (8 - column % 8);
if (view->text_wrap_mode && col >= width && width != 0) {
row += col / width;
col %= width;
}
continue;
}
if (view->search_start <= from && from < view->search_end) {
tty_setcolor (SELECTED_COLOR);
}
if (col >= view->dpy_text_column && col - view->dpy_text_column < width) {
widget_move (view, top + row, left + (col - view->dpy_text_column));
#ifdef HAVE_CHARSET
if (utf8_display) {
if (!view->utf8) {
c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
}
if (!g_unichar_isprint (c))
c = '.';
} else {
if (view->utf8) {
c = convert_from_utf_to_current_c (c, view->converter);
} else {
#endif
c = convert_to_display_c (c);
#ifdef HAVE_CHARSET
}
}
#endif
tty_print_anychar (c);
}
col++;
tty_setcolor (NORMAL_COLOR);
}
view->dpy_end = from;
}
/* --------------------------------------------------------------------------------------------- */
int
mcview__get_nroff_real_len (mcview_t * view, off_t start, off_t length)
{
mcview_nroff_t *nroff;
int ret = 0;
off_t i = 0;
nroff = mcview_nroff_seq_new_num (view, start);
if (nroff == NULL)
return 0;
while (i < length) {
if (nroff->type != NROFF_TYPE_NONE) {
ret += 2;
}
i++;
mcview_nroff_seq_next (nroff);
}
mcview_nroff_seq_free (&nroff);
return ret;
}
/* --------------------------------------------------------------------------------------------- */
mcview_nroff_t *
mcview_nroff_seq_new_num (mcview_t * view, off_t index)
{
mcview_nroff_t *nroff;
nroff = g_malloc0 (sizeof (mcview_nroff_t));
if (nroff == NULL)
return NULL;
nroff->index = index;
nroff->view = view;
mcview_nroff_seq_info (nroff);
return nroff;
}
/* --------------------------------------------------------------------------------------------- */
mcview_nroff_t *
mcview_nroff_seq_new (mcview_t * view)
{
return mcview_nroff_seq_new_num (view, (off_t) 0);
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_nroff_seq_free (mcview_nroff_t ** nroff)
{
if (nroff == NULL || *nroff == NULL)
return;
g_free (*nroff);
nroff = NULL;
}
/* --------------------------------------------------------------------------------------------- */
nroff_type_t
mcview_nroff_seq_info (mcview_nroff_t * nroff)
{
int next, next2;
if (nroff == NULL)
return NROFF_TYPE_NONE;
nroff->type = NROFF_TYPE_NONE;
if (! mcview_get_byte (nroff->view, nroff->index, &nroff->current_char)
|| !g_ascii_isprint (nroff->current_char)) /* FIXME: utf-8 and g_ascii_isprint */
return nroff->type;
nroff->char_width = 1;
if (! mcview_get_byte (nroff->view, nroff->index + 1, &next) || next != '\b')
return nroff->type;
if (! mcview_get_byte (nroff->view, nroff->index + 2, &next2)
|| !g_ascii_isprint (next2)) /* FIXME: utf-8 and g_ascii_isprint */
return nroff->type;
if (nroff->current_char == '_' && next2 == '_') {
nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD)
? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE;
} else if (nroff->current_char == next2) {
nroff->type = NROFF_TYPE_BOLD;
} else if (nroff->current_char == '_') {
nroff->current_char = next2;
nroff->type = NROFF_TYPE_UNDERLINE;
} else if (nroff->current_char == '+' && next2 == 'o') {
/* ??? */
}
return nroff->type;
}
/* --------------------------------------------------------------------------------------------- */
int
mcview_nroff_seq_next (mcview_nroff_t * nroff)
{
if (nroff == NULL)
return -1;
nroff->prev_type = nroff->type;
nroff->index += nroff->char_width;
if (nroff->prev_type != NROFF_TYPE_NONE)
nroff->index += 2;
mcview_nroff_seq_info (nroff);
return nroff->current_char;
}
/* --------------------------------------------------------------------------------------------- */

161
src/viewer/plain.c Normal file
View File

@ -0,0 +1,161 @@
/*
Internal file viewer for the Midnight Commander
Function for plain view
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 "../src/global.h"
#include "../src/main.h"
#include "../src/charsets.h"
#include "../src/tty/tty.h"
#include "../src/tty/color.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_text (mcview_t * view)
{
const screen_dimen left = view->data_area.left;
const screen_dimen top = view->data_area.top;
const screen_dimen width = view->data_area.width;
const screen_dimen height = view->data_area.height;
screen_dimen row, col;
off_t from;
int cw = 1;
int c;
gboolean read_res = TRUE;
struct hexedit_change_node *curr = view->change_list;
mcview_display_clean (view);
mcview_display_ruler (view);
/* Find the first displayable changed byte */
from = view->dpy_start;
while (curr && (curr->offset < from)) {
curr = curr->next;
}
tty_setcolor (NORMAL_COLOR);
for (row = 0, col = 0; row < height;) {
#ifdef HAVE_CHARSET
if (view->utf8) {
c = mcview_get_utf (view, from, &cw, &read_res);
if (!read_res)
break;
} else
#endif
{
if (! mcview_get_byte (view, from, &c))
break;
}
from++;
if (cw > 1)
from += cw - 1;
if ((c == '\n') || (col >= width && view->text_wrap_mode)) {
col = 0;
row++;
if (c == '\n' || row >= height)
continue;
}
if (c == '\r') {
if (! mcview_get_byte_indexed (view, from, 1, &c))
break;
if (c == '\r' || c == '\n')
continue;
col = 0;
row++;
continue;
}
if (c == '\t') {
off_t line, column;
mcview_offset_to_coord (view, &line, &column, from);
col += (8 - column % 8);
if (view->text_wrap_mode && col >= width && width != 0) {
row += col / width;
col %= width;
}
continue;
}
if (view->search_start <= from && from < view->search_end) {
tty_setcolor (SELECTED_COLOR);
}
if (col >= view->dpy_text_column && col - view->dpy_text_column < width) {
widget_move (view, top + row, left + (col - view->dpy_text_column));
#ifdef HAVE_CHARSET
if (utf8_display) {
if (!view->utf8) {
c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
}
if (!g_unichar_isprint (c))
c = '.';
} else {
if (view->utf8) {
c = convert_from_utf_to_current_c (c, view->converter);
} else {
#endif
c = convert_to_display_c (c);
#ifdef HAVE_CHARSET
}
}
#endif
tty_print_anychar (c);
}
col++;
tty_setcolor (NORMAL_COLOR);
}
view->dpy_end = from;
}
/* --------------------------------------------------------------------------------------------- */

254
src/viewer/search.c Normal file
View File

@ -0,0 +1,254 @@
/*
Internal file viewer for the Midnight Commander
Function for search data
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 "../src/global.h"
#include "../src/setup.h"
#include "../src/wtools.h"
#include "../src/tty/tty.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
static void
mcview_search_update_steps (mcview_t * view)
{
off_t filesize = mcview_get_filesize (view);
if (filesize != 0)
view->update_steps = 40000;
else /* viewing a data stream, not a file */
view->update_steps = filesize / 100;
/* Do not update the percent display but every 20 ks */
if (view->update_steps < 20000)
view->update_steps = 20000;
}
/* --------------------------------------------------------------------------------------------- */
static gboolean
mcview_find (mcview_t * view, gsize search_start, gsize * len)
{
gsize search_end;
view->search_numNeedSkipChar = 0;
if (view->search_backwards) {
search_end = mcview_get_filesize (view);
while ((int) search_start >= 0) {
view->search_nroff_seq->index = search_start;
mcview_nroff_seq_info (view->search_nroff_seq);
if (search_end > search_start + view->search->original_len
&& mc_search_is_fixed_search_str (view->search))
search_end = search_start + view->search->original_len;
if (mc_search_run (view->search, (void *) view, search_start, search_end, len)
&& view->search->normal_offset == search_start)
return TRUE;
search_start--;
}
view->search->error_str = g_strdup (_(" Search string not found "));
return FALSE;
}
view->search_nroff_seq->index = search_start;
mcview_nroff_seq_info (view->search_nroff_seq);
return mc_search_run (view->search, (void *) view, search_start, mcview_get_filesize (view),
len);
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
int
mcview_search_cmd_callback (const void *user_data, gsize char_offset)
{
int byte;
mcview_t *view = (mcview_t *) user_data;
/* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */
if (!view->text_nroff_mode) {
if (! mcview_get_byte (view, char_offset, &byte))
return MC_SEARCH_CB_ABORT;
return byte;
}
if (view->search_numNeedSkipChar) {
view->search_numNeedSkipChar--;
return MC_SEARCH_CB_SKIP;
}
byte = view->search_nroff_seq->current_char;
if (byte == -1)
return MC_SEARCH_CB_ABORT;
mcview_nroff_seq_next (view->search_nroff_seq);
if (view->search_nroff_seq->type != NROFF_TYPE_NONE)
view->search_numNeedSkipChar = 2;
return byte;
}
/* --------------------------------------------------------------------------------------------- */
int
mcview_search_update_cmd_callback (const void *user_data, gsize char_offset)
{
mcview_t *view = (mcview_t *) user_data;
if (char_offset >= view->update_activate) {
view->update_activate += view->update_steps;
if (verbose) {
mcview_percent (view, char_offset);
tty_refresh ();
}
if (tty_got_interrupt ())
return MC_SEARCH_CB_ABORT;
}
/* may be in future return from this callback will change current position
* in searching block. Now this just constant return value.
*/
return 1;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_do_search (mcview_t * view)
{
off_t search_start;
gboolean isFound = FALSE;
Dlg_head *d = NULL;
size_t match_len;
if (verbose) {
d = create_message (D_NORMAL, _("Search"), _("Searching %s"), view->last_search_string);
tty_refresh ();
}
/*for avoid infinite search loop we need to increase or decrease start offset of search */
if (view->search_start) {
search_start = (view->search_backwards) ? -2 : 2;
search_start = view->search_start + search_start +
mcview__get_nroff_real_len (view, view->search_start, 2) * search_start;
} else {
search_start = view->search_start;
}
if (view->search_backwards && (int) search_start < 0)
search_start = 0;
/* Compute the percent steps */
mcview_search_update_steps (view);
view->update_activate = 0;
tty_enable_interrupt_key ();
do {
if (mcview_find (view, search_start, &match_len)) {
view->search_start = view->search->normal_offset +
mcview__get_nroff_real_len (view,
view->search->start_buffer,
view->search->normal_offset -
view->search->start_buffer);
if (!view->hex_mode)
view->search_start++;
view->search_end = view->search_start + match_len +
mcview__get_nroff_real_len (view, view->search_start - 1, match_len);
if (view->hex_mode) {
view->hex_cursor = view->search_start;
view->hexedit_lownibble = FALSE;
view->dpy_start = view->search_start - view->search_start % view->bytes_per_line;
view->dpy_end = view->search_end - view->search_end % view->bytes_per_line;
}
if (verbose) {
dlg_run_done (d);
destroy_dlg (d);
d = create_message (D_NORMAL, _("Search"), _("Seeking to search result"));
tty_refresh ();
}
mcview_moveto_match (view);
isFound = TRUE;
break;
}
} while (mcview_may_still_grow (view));
if (!isFound) {
if (view->search->error_str)
message (D_NORMAL, _("Search"), "%s", view->search->error_str);
}
view->dirty++;
mcview_update (view);
tty_disable_interrupt_key ();
if (verbose) {
dlg_run_done (d);
destroy_dlg (d);
}
}
/* --------------------------------------------------------------------------------------------- */