2005-04-14 02:19:52 +04:00
|
|
|
/*
|
|
|
|
Internal file viewer for the Midnight Commander
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
Copyright (C) 1994, 1995, 1996 The Free Software Foundation
|
2005-04-14 02:19:52 +04:00
|
|
|
|
1998-04-09 08:58:24 +04:00
|
|
|
Written by: 1994, 1995, 1998 Miguel de Icaza
|
2005-07-03 19:31:55 +04:00
|
|
|
1994, 1995 Janne Kukonlehto
|
|
|
|
1995 Jakub Jelinek
|
|
|
|
1996 Joseph M. Hinkle
|
1998-02-27 07:54:42 +03:00
|
|
|
1997 Norbert Warmuth
|
1998-11-03 00:47:06 +03:00
|
|
|
1998 Pavel Machek
|
2004-12-02 20:13:39 +03:00
|
|
|
2004 Roland Illig <roland.illig@gmx.de>
|
2005-02-08 01:31:30 +03:00
|
|
|
2005 Roland Illig <roland.illig@gmx.de>
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
This program 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.
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
This program 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
|
2005-05-27 07:35:10 +04:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2005-04-14 02:19:52 +04:00
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-02-08 01:31:30 +03:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
#endif
|
2005-02-08 01:31:30 +03:00
|
|
|
|
2005-04-07 15:23:53 +04:00
|
|
|
#include <assert.h>
|
2005-02-08 01:31:30 +03:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdio.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <stdlib.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <string.h>
|
2005-02-08 01:31:30 +03:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <sys/stat.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <unistd.h>
|
2001-08-07 20:53:55 +04:00
|
|
|
|
Glibing..... (2)
Wed Jan 27 03:17:44 1999 Timur Bakeyev <mc@bat.ru>
* Converted memory managment to Glib. Now we use g_new()/g_malloc()/
g_strdup()/g_free() routings. Also, copy_strings() replaced by
g_strconcat(), strcasecmp() -> g_strcasecmp(),and sprintf() by
g_snprintf().
* Some sequences of malloc()/sprintf() changed to g_strdup_printf().
* mad.[ch]: Modified, to work with new GLib's memory managment. Fixed
a missing #undef for tempnam, which caused dead loop. Add several new
functions to emulate GLib memory managment.
*main.c, mad.[ch]: Add a new switch "-M", which allows to redirect MAD
messages to the file.
* util.[ch], utilunix.c: Modified, deleted our variants of strcasecmp()
and strdup() - we have g_ equivalences. Remove get_full_name() - it is
similar to concat_dir_and_file(). Some other tricks with g_* functions.
* global.h: Modified, extended. Now it is main memory mangment include -
i.e. all inclusions of <stdlib.h>, <malloc.h>, <glib.h>, "fs.h", "mem.h",
"util.h" and "mad.h" done there. This elimanates problem with proper or-
der of #include's.
* All around the source - changed order of #include's, most of them gone
to global.h (see above), minor changes, like "0" -> NULL in string func-
tions.
1999-01-27 04:08:30 +03:00
|
|
|
#include "global.h"
|
2001-08-07 20:53:55 +04:00
|
|
|
#include "tty.h"
|
|
|
|
#include "cmd.h" /* For view_other_cmd */
|
2003-10-25 03:20:30 +04:00
|
|
|
#include "dialog.h" /* Needed by widget.h */
|
1998-02-27 07:54:42 +03:00
|
|
|
#include "widget.h" /* Needed for buttonbar_new */
|
|
|
|
#include "color.h"
|
|
|
|
#include "mouse.h"
|
|
|
|
#include "help.h"
|
|
|
|
#include "key.h" /* For mi_getch() */
|
|
|
|
#include "layout.h"
|
1998-11-18 05:31:23 +03:00
|
|
|
#include "setup.h"
|
1998-02-27 07:54:42 +03:00
|
|
|
#include "wtools.h" /* For query_set_sel() */
|
|
|
|
#include "dir.h"
|
2002-10-31 01:48:59 +03:00
|
|
|
#include "panel.h" /* Needed for current_panel and other_panel */
|
1998-02-27 07:54:42 +03:00
|
|
|
#include "win.h"
|
2003-06-22 13:17:46 +04:00
|
|
|
#include "execute.h"
|
2005-05-11 01:38:40 +04:00
|
|
|
#include "main.h" /* slow_terminal */
|
1998-02-27 07:54:42 +03:00
|
|
|
#include "view.h"
|
|
|
|
|
2001-06-06 02:49:15 +04:00
|
|
|
#include "charsets.h"
|
2001-06-25 15:24:49 +04:00
|
|
|
#include "selcodepage.h"
|
2001-06-06 02:49:15 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Block size for reading files in parts */
|
2005-04-14 02:18:04 +04:00
|
|
|
#define VIEW_PAGE_SIZE ((size_t) 8192)
|
2005-05-26 13:08:54 +04:00
|
|
|
#define VIEW_COORD_CACHE_GRANUL 1024
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-04-16 19:13:20 +04:00
|
|
|
typedef unsigned char byte;
|
|
|
|
|
2004-08-16 08:16:55 +04:00
|
|
|
/* Offset in bytes into a file */
|
|
|
|
typedef unsigned long offset_type;
|
2004-10-16 19:52:48 +04:00
|
|
|
#define INVALID_OFFSET ((offset_type) -1)
|
2004-12-02 20:13:39 +03:00
|
|
|
#define OFFSETTYPE_MAX (~((offset_type) 0))
|
2005-04-25 04:26:46 +04:00
|
|
|
#define OFFSETTYPE_PRIX "lX"
|
|
|
|
#define OFFSETTYPE_PRId "lu"
|
2004-08-16 08:16:55 +04:00
|
|
|
|
|
|
|
/* A width or height on the screen */
|
|
|
|
typedef unsigned int screen_dimen;
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
/* 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 {
|
|
|
|
offset_type cc_offset;
|
|
|
|
offset_type cc_line;
|
|
|
|
offset_type cc_column;
|
|
|
|
offset_type cc_nroff_column;
|
|
|
|
};
|
|
|
|
|
2002-11-15 00:18:28 +03:00
|
|
|
/* A node for building a change list on change_list */
|
|
|
|
struct hexedit_change_node {
|
|
|
|
struct hexedit_change_node *next;
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type offset;
|
2005-04-16 19:13:20 +04:00
|
|
|
byte value;
|
2002-11-15 00:18:28 +03:00
|
|
|
};
|
|
|
|
|
2005-04-07 15:23:53 +04:00
|
|
|
/* 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 */
|
|
|
|
};
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
struct area {
|
|
|
|
screen_dimen top, left;
|
|
|
|
screen_dimen height, width;
|
|
|
|
};
|
|
|
|
|
2002-11-15 00:18:28 +03:00
|
|
|
struct WView {
|
|
|
|
Widget widget;
|
|
|
|
|
|
|
|
char *filename; /* Name of the file */
|
|
|
|
char *command; /* Command used to pipe data in */
|
2005-01-31 00:17:29 +03:00
|
|
|
|
2005-04-07 15:23:53 +04:00
|
|
|
enum view_ds datasource; /* Where the displayed data comes from */
|
|
|
|
|
|
|
|
/* stdio pipe data source */
|
2005-04-16 16:56:50 +04:00
|
|
|
FILE *ds_stdio_pipe; /* Output of a shell command */
|
2002-11-15 00:18:28 +03:00
|
|
|
|
2005-04-07 15:23:53 +04:00
|
|
|
/* vfs pipe data source */
|
2005-04-16 16:56:50 +04:00
|
|
|
int ds_vfs_pipe; /* Non-seekable vfs file descriptor */
|
2005-04-07 15:23:53 +04:00
|
|
|
|
|
|
|
/* vfs file data source */
|
2005-04-16 16:56:50 +04:00
|
|
|
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 */
|
2005-04-16 19:13:20 +04:00
|
|
|
byte *ds_file_data; /* Currently loaded data */
|
2005-04-07 15:23:53 +04:00
|
|
|
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 */
|
2005-04-16 19:13:20 +04:00
|
|
|
byte *ds_string_data; /* The characters of the string */
|
2005-04-07 15:23:53 +04:00
|
|
|
size_t ds_string_len; /* The length of the string */
|
2002-11-15 00:18:28 +03:00
|
|
|
|
2005-04-19 00:06:16 +04:00
|
|
|
/* 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
|
2005-07-03 19:31:55 +04:00
|
|
|
growing buffer */
|
2005-04-19 00:06:16 +04:00
|
|
|
gboolean growbuf_finished; /* TRUE when all data has been read. */
|
|
|
|
|
2005-04-14 14:59:02 +04:00
|
|
|
/* Editor modes */
|
2005-04-14 15:02:21 +04:00
|
|
|
gboolean hex_mode; /* Hexview or Hexedit */
|
2005-04-14 15:08:25 +04:00
|
|
|
gboolean hexedit_mode; /* Hexedit */
|
2005-04-14 14:59:02 +04:00
|
|
|
gboolean hexview_in_text; /* Is the hexview cursor in the text area? */
|
2005-04-14 15:06:12 +04:00
|
|
|
gboolean text_nroff_mode; /* Nroff-style highlighting */
|
2005-04-14 15:14:42 +04:00
|
|
|
gboolean text_wrap_mode; /* Wrap text lines to fit them on the screen */
|
2005-04-14 15:12:01 +04:00
|
|
|
gboolean magic_mode; /* Preprocess the file using external programs */
|
2005-04-14 14:59:02 +04:00
|
|
|
|
2005-04-20 00:33:51 +04:00
|
|
|
/* Additional editor state */
|
|
|
|
gboolean hexedit_lownibble; /* Are we editing the last significant nibble? */
|
2005-05-26 13:08:54 +04:00
|
|
|
GArray *coord_cache; /* Cache for mapping offsets to cursor positions */
|
2005-04-20 00:33:51 +04:00
|
|
|
|
2002-11-15 00:18:28 +03:00
|
|
|
/* Display information */
|
2005-07-06 23:12:25 +04:00
|
|
|
screen_dimen dpy_frame_size;/* Size of the frame surrounding the real viewer */
|
2005-05-21 14:17:35 +04:00
|
|
|
offset_type dpy_topleft; /* Offset of the byte in the top left corner */
|
|
|
|
offset_type dpy_text_column;/* Number of skipped columns in non-wrap
|
|
|
|
* text mode */
|
2005-05-21 14:21:35 +04:00
|
|
|
gboolean dpy_complete; /* Has the last call to display() reached the
|
|
|
|
* end of file? */
|
2005-05-21 14:23:57 +04:00
|
|
|
offset_type hex_cursor; /* Hexview cursor position in file */
|
2004-08-16 08:16:55 +04:00
|
|
|
screen_dimen cursor_col; /* Cursor column */
|
|
|
|
screen_dimen cursor_row; /* Cursor row */
|
2002-11-15 00:18:28 +03:00
|
|
|
struct hexedit_change_node *change_list; /* Linked list of changes */
|
2005-07-06 23:12:25 +04:00
|
|
|
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 */
|
2002-11-15 00:18:28 +03:00
|
|
|
|
|
|
|
int dirty; /* Number of skipped updates */
|
2005-01-31 00:17:29 +03:00
|
|
|
|
2002-11-15 00:18:28 +03:00
|
|
|
/* Mode variables */
|
|
|
|
int bytes_per_line; /* Number of bytes per line in hex mode */
|
2005-01-31 00:17:29 +03:00
|
|
|
|
2002-11-15 00:18:28 +03:00
|
|
|
/* Search variables */
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type search_start; /* First character to start searching from */
|
|
|
|
offset_type found_len; /* Length of found string or 0 if none was found */
|
2002-11-15 00:18:28 +03:00
|
|
|
char *search_exp; /* The search expression */
|
|
|
|
int direction; /* 1= forward; -1 backward */
|
2005-06-28 16:28:35 +04:00
|
|
|
void (*last_search)(WView *, char *);
|
2005-07-03 19:31:55 +04:00
|
|
|
/* Pointer to the last search command */
|
2005-06-28 02:38:03 +04:00
|
|
|
gboolean want_to_quit; /* Prepare for cleanup ... */
|
2002-11-15 00:18:28 +03:00
|
|
|
|
|
|
|
/* Markers */
|
|
|
|
int marker; /* mark to use */
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type marks [10]; /* 10 marks: 0..9 */
|
2005-01-31 00:17:29 +03:00
|
|
|
|
|
|
|
int move_dir; /* return value from widget:
|
2002-11-15 00:18:28 +03:00
|
|
|
* 0 do nothing
|
|
|
|
* -1 view previous file
|
|
|
|
* 1 view next file
|
|
|
|
*/
|
2005-02-01 01:01:53 +03:00
|
|
|
|
|
|
|
offset_type update_steps; /* The number of bytes between percent
|
2005-07-03 19:31:55 +04:00
|
|
|
* increments */
|
2005-02-01 01:01:53 +03:00
|
|
|
offset_type update_activate;/* Last point where we updated the status */
|
2002-11-15 00:18:28 +03:00
|
|
|
};
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
|
|
|
|
/* {{{ Global Variables }}} */
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Maxlimit for skipping updates */
|
2003-07-23 07:22:32 +04:00
|
|
|
int max_dirt_limit = 10;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* If set, show a ruler */
|
2005-07-06 23:12:25 +04:00
|
|
|
static enum {
|
|
|
|
RULER_NONE,
|
|
|
|
RULER_TOP,
|
|
|
|
RULER_BOTTOM
|
|
|
|
} ruler = RULER_NONE;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Scrolling is done in pages or line increments */
|
|
|
|
int mouse_move_pages_viewer = 1;
|
|
|
|
|
1998-03-14 03:42:23 +03:00
|
|
|
/* wrap mode default */
|
|
|
|
int global_wrap_mode = 1;
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
int default_hex_mode = 0;
|
2002-08-27 23:10:54 +04:00
|
|
|
static int default_hexedit_mode = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
int default_magic_flag = 1;
|
|
|
|
int default_nroff_flag = 1;
|
|
|
|
int altered_hex_mode = 0;
|
|
|
|
int altered_magic_flag = 0;
|
|
|
|
int altered_nroff_flag = 0;
|
|
|
|
|
1999-12-10 19:04:35 +03:00
|
|
|
static const char hex_char[] = "0123456789ABCDEF";
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-18 12:47:45 +04:00
|
|
|
int mcview_remember_file_position = FALSE;
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
/* {{{ Function Prototypes }}} */
|
|
|
|
|
2003-09-11 02:48:54 +04:00
|
|
|
/* Our widget callback */
|
2005-06-28 03:19:32 +04:00
|
|
|
static cb_ret_t view_callback (Widget *, widget_msg_t, int);
|
2002-08-27 23:10:54 +04:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
static int regexp_view_search (WView * view, char *pattern, char *string,
|
|
|
|
int match_type);
|
|
|
|
static void view_labels (WView * view);
|
2002-08-27 23:10:54 +04:00
|
|
|
|
2005-04-14 12:00:14 +04:00
|
|
|
static void view_init_growbuf (WView *);
|
2005-04-17 13:05:42 +04:00
|
|
|
static void view_place_cursor (WView *view);
|
2005-07-14 01:30:28 +04:00
|
|
|
static void display (WView *);
|
2005-04-14 12:00:14 +04:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
/* {{{ Helper Functions }}} */
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
/* difference or zero */
|
|
|
|
static inline screen_dimen
|
|
|
|
dimen_doz (screen_dimen a, screen_dimen b)
|
|
|
|
{
|
|
|
|
return (a >= b) ? a - b : 0;
|
|
|
|
}
|
|
|
|
|
2005-07-07 21:49:01 +04:00
|
|
|
static inline screen_dimen
|
|
|
|
dimen_min (screen_dimen a, screen_dimen b)
|
|
|
|
{
|
|
|
|
return (a < b) ? a : b;
|
|
|
|
}
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
static inline offset_type
|
|
|
|
offset_doz (offset_type a, offset_type b)
|
|
|
|
{
|
|
|
|
return (a >= b) ? a - b : 0;
|
|
|
|
}
|
|
|
|
|
2005-06-28 02:36:00 +04:00
|
|
|
static inline offset_type
|
2005-05-26 13:08:54 +04:00
|
|
|
offset_rounddown (offset_type a, offset_type b)
|
|
|
|
{
|
2005-07-07 02:35:17 +04:00
|
|
|
assert (b != 0);
|
2005-05-26 13:08:54 +04:00
|
|
|
return a - a % b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ Simple Primitive Functions for WView }}} */
|
|
|
|
|
2005-04-16 17:45:16 +04:00
|
|
|
static inline gboolean
|
|
|
|
view_is_in_panel (WView *view)
|
|
|
|
{
|
|
|
|
return (view->dpy_frame_size != 0);
|
|
|
|
}
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
static void
|
|
|
|
view_compute_areas (WView *view)
|
2005-04-17 14:14:18 +04:00
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
struct area view_area;
|
2005-07-07 21:49:01 +04:00
|
|
|
screen_dimen height, rest, y;
|
2005-04-17 14:14:18 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
/* 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. */
|
2005-04-17 14:14:18 +04:00
|
|
|
|
2005-07-07 20:48:55 +04:00
|
|
|
view_area.top = view->dpy_frame_size;
|
|
|
|
view_area.left = view->dpy_frame_size;
|
2005-07-06 23:12:25 +04:00
|
|
|
view_area.height = dimen_doz(view->widget.lines, 2 * view->dpy_frame_size);
|
|
|
|
view_area.width = dimen_doz(view->widget.cols, 2 * view->dpy_frame_size);
|
2005-04-17 14:14:18 +04:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
/* Most coordinates of the areas equal those of the whole viewer */
|
2005-07-06 23:12:25 +04:00
|
|
|
view->status_area = view_area;
|
|
|
|
view->ruler_area = view_area;
|
|
|
|
view->data_area = view_area;
|
2005-04-14 04:43:34 +04:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
/* Compute the heights of the areas */
|
2005-07-07 21:49:01 +04:00
|
|
|
rest = view_area.height;
|
|
|
|
height = dimen_min(rest, 1);
|
|
|
|
view->status_area.height = height;
|
|
|
|
rest -= height;
|
|
|
|
height = dimen_min(rest, (ruler == RULER_NONE || view->hex_mode) ? 0 : 2);
|
|
|
|
view->ruler_area.height = height;
|
|
|
|
rest -= height;
|
|
|
|
view->data_area.height = rest;
|
2005-04-16 22:53:51 +04:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
/* Compute the position of the areas */
|
2005-07-06 23:12:25 +04:00
|
|
|
y = view->status_area.top + 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;
|
|
|
|
}
|
2005-04-16 22:53:51 +04:00
|
|
|
}
|
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
/* {{{ Growing buffer }}} */
|
2005-05-26 13:08:54 +04:00
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
static void
|
|
|
|
view_init_growbuf (WView *view)
|
|
|
|
{
|
|
|
|
view->growbuf_in_use = TRUE;
|
|
|
|
view->growbuf_blockptr = NULL;
|
|
|
|
view->growbuf_blocks = 0;
|
|
|
|
view->growbuf_lastindex = 0;
|
|
|
|
view->growbuf_finished = FALSE;
|
|
|
|
}
|
2005-05-26 14:04:26 +04:00
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
static void
|
|
|
|
view_growbuf_free (WView *view)
|
|
|
|
{
|
|
|
|
size_t i;
|
2005-05-26 14:04:26 +04:00
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
assert (view->growbuf_in_use);
|
2005-05-26 14:04:26 +04:00
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
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;
|
|
|
|
}
|
2005-05-26 13:08:54 +04:00
|
|
|
|
2005-05-26 13:51:03 +04:00
|
|
|
static offset_type
|
2005-06-14 18:13:11 +04:00
|
|
|
view_growbuf_filesize (WView *view)
|
2005-05-26 13:51:03 +04:00
|
|
|
{
|
|
|
|
assert(view->growbuf_in_use);
|
|
|
|
|
|
|
|
if (view->growbuf_blocks == 0)
|
2005-07-03 19:31:55 +04:00
|
|
|
return 0;
|
2005-05-26 13:51:03 +04:00
|
|
|
else
|
2005-07-03 19:31:55 +04:00
|
|
|
return ((offset_type) view->growbuf_blocks - 1)
|
2005-05-26 13:51:03 +04:00
|
|
|
* VIEW_PAGE_SIZE + view->growbuf_lastindex;
|
|
|
|
}
|
|
|
|
|
2005-05-26 13:34:44 +04:00
|
|
|
/* Copies the output from the pipe to the growing buffer, until either
|
|
|
|
* the end-of-pipe is reached or the interval [0..ofs) or the growing
|
|
|
|
* buffer is completely filled. */
|
|
|
|
static void
|
|
|
|
view_growbuf_read_until (WView *view, offset_type ofs)
|
|
|
|
{
|
|
|
|
ssize_t nread;
|
|
|
|
byte *p;
|
|
|
|
size_t bytesfree;
|
2005-08-06 22:19:14 +04:00
|
|
|
gboolean short_read;
|
2005-05-26 13:34:44 +04:00
|
|
|
|
|
|
|
assert (view->growbuf_in_use);
|
|
|
|
|
|
|
|
if (view->growbuf_finished)
|
|
|
|
return;
|
|
|
|
|
2005-08-06 22:19:14 +04:00
|
|
|
short_read = FALSE;
|
|
|
|
while (view_growbuf_filesize (view) < ofs || short_read) {
|
2005-07-03 19:31:55 +04:00
|
|
|
if (view->growbuf_blocks == 0 || view->growbuf_lastindex == VIEW_PAGE_SIZE) {
|
2005-07-12 10:04:38 +04:00
|
|
|
/* Append a new block to the growing buffer */
|
2005-07-03 19:31:55 +04:00
|
|
|
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);
|
2005-05-26 13:34:44 +04:00
|
|
|
g_free (newblocks);
|
2005-07-03 19:31:55 +04:00
|
|
|
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;
|
2005-05-26 13:34:44 +04:00
|
|
|
|
|
|
|
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);
|
2005-07-14 01:30:28 +04:00
|
|
|
display (view);
|
2005-05-26 13:34:44 +04:00
|
|
|
close_error_pipe (0, NULL);
|
|
|
|
view->ds_stdio_pipe = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2005-07-01 02:50:30 +04:00
|
|
|
assert (view->datasource == DS_VFS_PIPE);
|
2005-08-15 14:04:49 +04:00
|
|
|
do {
|
|
|
|
nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
|
|
|
|
} while (nread == -1 && errno == EINTR);
|
2005-05-26 13:34:44 +04:00
|
|
|
if (nread == -1 || nread == 0) {
|
|
|
|
view->growbuf_finished = TRUE;
|
|
|
|
(void) mc_close (view->ds_vfs_pipe);
|
|
|
|
view->ds_vfs_pipe = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-08-06 22:19:14 +04:00
|
|
|
short_read = (nread < bytesfree);
|
2005-07-03 19:31:55 +04:00
|
|
|
view->growbuf_lastindex += nread;
|
2005-05-26 13:34:44 +04:00
|
|
|
}
|
2005-05-26 14:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_byte_growing_buffer (WView *view, offset_type byte_index)
|
|
|
|
{
|
|
|
|
offset_type pageno = byte_index / VIEW_PAGE_SIZE;
|
|
|
|
offset_type pageindex = byte_index % VIEW_PAGE_SIZE;
|
|
|
|
|
|
|
|
assert (view->growbuf_in_use);
|
|
|
|
|
|
|
|
if ((size_t) pageno != pageno)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
view_growbuf_read_until (view, byte_index + 1);
|
|
|
|
if (view->growbuf_blocks == 0)
|
|
|
|
return -1;
|
|
|
|
if (pageno < view->growbuf_blocks - 1)
|
|
|
|
return view->growbuf_blockptr[pageno][pageindex];
|
|
|
|
if (pageno == view->growbuf_blocks - 1 && pageindex < view->growbuf_lastindex)
|
|
|
|
return view->growbuf_blockptr[pageno][pageindex];
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ Data sources }}} */
|
|
|
|
|
|
|
|
/*
|
|
|
|
The data source provides the viewer with data from either a file, a
|
|
|
|
string or the output of a command. The 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 get_byte_indexed(a,b)
|
|
|
|
returns the byte at the offset a+b, or -1 if a+b is out of range.
|
|
|
|
|
|
|
|
The view_set_byte() function has the effect that later calls to
|
|
|
|
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 view_get_filesize() function returns the current size of the
|
|
|
|
data source. If the growing buffer is used, this size may increase
|
2005-07-12 10:04:38 +04:00
|
|
|
later on. Use the view_may_still_grow() function when you want to
|
2005-05-26 14:17:38 +04:00
|
|
|
know if the size can change later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static offset_type
|
2005-06-14 18:13:11 +04:00
|
|
|
view_get_filesize (WView *view)
|
2005-05-26 14:17:38 +04:00
|
|
|
{
|
|
|
|
switch (view->datasource) {
|
|
|
|
case DS_NONE:
|
|
|
|
return 0;
|
|
|
|
case DS_STDIO_PIPE:
|
|
|
|
case DS_VFS_PIPE:
|
2005-06-14 18:13:11 +04:00
|
|
|
return view_growbuf_filesize (view);
|
2005-05-26 14:17:38 +04:00
|
|
|
case DS_FILE:
|
|
|
|
return view->ds_file_filesize;
|
|
|
|
case DS_STRING:
|
|
|
|
return view->ds_string_len;
|
|
|
|
default:
|
|
|
|
assert(!"Unknown datasource type");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-28 02:36:00 +04:00
|
|
|
static inline gboolean
|
2005-06-14 18:13:11 +04:00
|
|
|
view_may_still_grow (WView *view)
|
2005-05-26 14:17:38 +04:00
|
|
|
{
|
2005-06-14 18:13:11 +04:00
|
|
|
return (view->growbuf_in_use && !view->growbuf_finished);
|
2005-05-26 14:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns TRUE if the idx lies in the half-open interval
|
|
|
|
* [offset; offset + size), FALSE otherwise.
|
|
|
|
*/
|
2005-06-28 02:11:55 +04:00
|
|
|
static inline gboolean
|
2005-05-26 14:17:38 +04:00
|
|
|
already_loaded (offset_type offset, offset_type idx, size_t size)
|
|
|
|
{
|
|
|
|
return (offset <= idx && idx - offset < size);
|
|
|
|
}
|
|
|
|
|
2005-06-28 02:11:55 +04:00
|
|
|
static inline void
|
2005-05-26 14:17:38 +04:00
|
|
|
view_file_load_data (WView *view, offset_type byte_index)
|
|
|
|
{
|
|
|
|
offset_type blockoffset;
|
|
|
|
ssize_t res;
|
|
|
|
size_t bytes_read;
|
|
|
|
|
2005-07-01 03:16:14 +04:00
|
|
|
assert (view->datasource == DS_FILE);
|
2005-07-01 02:50:30 +04:00
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
if (already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
|
|
|
|
return;
|
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
blockoffset = offset_rounddown (byte_index, view->ds_file_datasize);
|
2005-05-26 14:17:38 +04:00
|
|
|
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:
|
2005-07-12 10:04:38 +04:00
|
|
|
view->ds_file_datalen = 0;
|
2005-05-26 14:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_byte_none (WView *view, offset_type byte_index)
|
|
|
|
{
|
|
|
|
assert (view->datasource == DS_NONE);
|
|
|
|
(void) &view;
|
|
|
|
(void) byte_index;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-06-28 02:11:55 +04:00
|
|
|
static inline int
|
2005-05-26 14:17:38 +04:00
|
|
|
get_byte_file (WView *view, offset_type byte_index)
|
|
|
|
{
|
|
|
|
assert (view->datasource == DS_FILE);
|
|
|
|
|
|
|
|
view_file_load_data (view, byte_index);
|
|
|
|
if (already_loaded(view->ds_file_offset, byte_index, view->ds_file_datalen))
|
|
|
|
return view->ds_file_data[byte_index - view->ds_file_offset];
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_byte_string (WView *view, offset_type byte_index)
|
|
|
|
{
|
|
|
|
assert (view->datasource == DS_STRING);
|
|
|
|
if (byte_index < view->ds_string_len)
|
|
|
|
return view->ds_string_data[byte_index];
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-06-28 02:11:55 +04:00
|
|
|
static inline int
|
2005-05-26 14:17:38 +04:00
|
|
|
get_byte (WView *view, offset_type offset)
|
|
|
|
{
|
|
|
|
switch (view->datasource) {
|
|
|
|
case DS_STDIO_PIPE:
|
|
|
|
case DS_VFS_PIPE:
|
|
|
|
return get_byte_growing_buffer (view, offset);
|
|
|
|
case DS_FILE:
|
|
|
|
return get_byte_file (view, offset);
|
|
|
|
case DS_STRING:
|
|
|
|
return get_byte_string (view, offset);
|
|
|
|
case DS_NONE:
|
|
|
|
return get_byte_none (view, offset);
|
|
|
|
}
|
|
|
|
assert(!"Unknown datasource type");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
get_byte_indexed (WView *view, offset_type base, offset_type ofs)
|
|
|
|
{
|
|
|
|
if (base <= OFFSETTYPE_MAX - ofs)
|
|
|
|
return get_byte (view, base + ofs);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_set_byte (WView *view, offset_type offset, byte b)
|
|
|
|
{
|
2005-07-03 18:01:25 +04:00
|
|
|
(void) &b;
|
2005-05-26 14:17:38 +04:00
|
|
|
assert (offset < view_get_filesize (view));
|
2005-07-01 02:50:30 +04:00
|
|
|
assert (view->datasource == DS_FILE);
|
|
|
|
view->ds_file_datalen = 0; /* just force reloading */
|
2005-05-26 14:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_set_datasource_none (WView *view)
|
|
|
|
{
|
|
|
|
view->datasource = DS_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_set_datasource_vfs_pipe (WView *view, int fd)
|
|
|
|
{
|
2005-07-01 02:50:30 +04:00
|
|
|
assert (fd != -1);
|
2005-05-26 14:17:38 +04:00
|
|
|
view->datasource = DS_VFS_PIPE;
|
|
|
|
view->ds_vfs_pipe = fd;
|
|
|
|
|
|
|
|
view_init_growbuf (view);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_set_datasource_stdio_pipe (WView *view, FILE *fp)
|
|
|
|
{
|
2005-07-01 02:50:30 +04:00
|
|
|
assert (fp != NULL);
|
2005-05-26 14:17:38 +04:00
|
|
|
view->datasource = DS_STDIO_PIPE;
|
|
|
|
view->ds_stdio_pipe = fp;
|
|
|
|
|
|
|
|
view_init_growbuf (view);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_set_datasource_string (WView *view, const char *s)
|
|
|
|
{
|
|
|
|
view->datasource = DS_STRING;
|
|
|
|
view->ds_string_data = (byte *) g_strdup (s);
|
|
|
|
view->ds_string_len = strlen (s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_set_datasource_file (WView *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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_close_datasource (WView *view)
|
|
|
|
{
|
|
|
|
switch (view->datasource) {
|
|
|
|
case DS_NONE:
|
|
|
|
break;
|
|
|
|
case DS_STDIO_PIPE:
|
|
|
|
if (view->ds_stdio_pipe != NULL) {
|
|
|
|
(void) pclose (view->ds_stdio_pipe);
|
2005-07-14 01:30:28 +04:00
|
|
|
display (view);
|
2005-05-26 14:17:38 +04:00
|
|
|
close_error_pipe (0, NULL);
|
|
|
|
view->ds_stdio_pipe = NULL;
|
|
|
|
}
|
|
|
|
view_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;
|
|
|
|
}
|
|
|
|
view_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;
|
2005-05-26 13:46:48 +04:00
|
|
|
}
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
/* {{{ The Coordinate Cache }}} */
|
|
|
|
|
|
|
|
/*
|
|
|
|
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 view_coord_to_offset() and
|
|
|
|
view_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().
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum ccache_type {
|
|
|
|
CCACHE_OFFSET,
|
|
|
|
CCACHE_LINECOL
|
|
|
|
};
|
|
|
|
|
2005-06-28 01:37:51 +04:00
|
|
|
static inline gboolean
|
2005-05-26 13:08:54 +04:00
|
|
|
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
|
2005-08-15 15:49:30 +04:00
|
|
|
static void view_coord_to_offset (WView *, offset_type *, offset_type, offset_type);
|
|
|
|
static void view_offset_to_coord (WView *, offset_type *, offset_type *, offset_type);
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
static void
|
|
|
|
view_ccache_dump (WView *view)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
offset_type offset, line, column, nextline_offset, filesize;
|
|
|
|
guint i;
|
|
|
|
const struct coord_cache_entry *cache;
|
|
|
|
|
|
|
|
assert (view->coord_cache != NULL);
|
|
|
|
|
|
|
|
filesize = view_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;
|
2005-08-15 15:49:30 +04:00
|
|
|
(void)setvbuf(f, NULL, _IONBF, 0);
|
2005-05-26 13:08:54 +04:00
|
|
|
|
|
|
|
/* 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++) {
|
|
|
|
view_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++) {
|
|
|
|
view_coord_to_offset (view, &nextline_offset, line + 1, 0);
|
2005-08-15 15:49:30 +04:00
|
|
|
(void)fprintf (f, "nextline_offset %8"OFFSETTYPE_PRId"\n",
|
|
|
|
nextline_offset);
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
for (column = 0; TRUE; column++) {
|
|
|
|
view_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
|
|
|
|
|
2005-06-28 02:36:00 +04:00
|
|
|
static inline gboolean
|
2005-06-07 11:06:48 +04:00
|
|
|
is_nroff_sequence (WView *view, offset_type offset)
|
|
|
|
{
|
2005-06-28 01:34:36 +04:00
|
|
|
int c0, c1, c2;
|
|
|
|
|
|
|
|
/* The following commands are ordered to speed up the calculation. */
|
2005-06-07 11:06:48 +04:00
|
|
|
|
|
|
|
c1 = get_byte_indexed (view, offset, 1);
|
2005-06-28 01:34:36 +04:00
|
|
|
if (c1 == -1 || c1 != '\b')
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
c0 = get_byte_indexed (view, offset, 0);
|
|
|
|
if (c0 == -1 || !is_printable(c0))
|
|
|
|
return FALSE;
|
|
|
|
|
2005-06-07 11:06:48 +04:00
|
|
|
c2 = get_byte_indexed (view, offset, 2);
|
2005-06-28 01:34:36 +04:00
|
|
|
if (c2 == -1 || !is_printable(c2))
|
|
|
|
return FALSE;
|
2005-06-07 11:06:48 +04:00
|
|
|
|
2005-06-28 01:34:36 +04:00
|
|
|
return (c0 == c2 || c0 == '_' || (c0 == '+' && c2 == 'o'));
|
2005-06-07 11:06:48 +04:00
|
|
|
}
|
|
|
|
|
2005-08-15 22:58:18 +04:00
|
|
|
/* Find and return the index of the last cache entry that is
|
|
|
|
* smaller than ''coord'', according to the criterion ''sort_by''. */
|
2005-07-08 01:46:01 +04:00
|
|
|
static inline guint
|
2005-07-08 02:34:31 +04:00
|
|
|
view_ccache_find (WView *view, const struct coord_cache_entry *cache,
|
2005-07-08 01:46:01 +04:00
|
|
|
const struct coord_cache_entry *coord, enum ccache_type sort_by)
|
|
|
|
{
|
2005-07-08 02:30:56 +04:00
|
|
|
guint base, i, limit;
|
|
|
|
|
|
|
|
limit = view->coord_cache->len;
|
|
|
|
assert (limit != 0);
|
|
|
|
|
|
|
|
base = 0;
|
|
|
|
while (limit > 1) {
|
|
|
|
i = base + limit / 2;
|
|
|
|
if (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;
|
2005-07-08 01:46:01 +04:00
|
|
|
}
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
/* 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''.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
view_ccache_lookup (WView *view, struct coord_cache_entry *coord,
|
|
|
|
enum ccache_type lookup_what)
|
|
|
|
{
|
|
|
|
guint i;
|
2005-08-15 15:49:30 +04:00
|
|
|
struct coord_cache_entry *cache, current, next, entry;
|
2005-05-26 13:08:54 +04:00
|
|
|
enum ccache_type sorter;
|
2005-06-07 11:06:48 +04:00
|
|
|
offset_type limit;
|
|
|
|
enum {
|
|
|
|
NROFF_START,
|
|
|
|
NROFF_BACKSPACE,
|
|
|
|
NROFF_CONTINUATION
|
|
|
|
} nroff_state;
|
2005-05-26 13:08:54 +04:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
retry:
|
|
|
|
/* find the two neighbor entries in the cache */
|
|
|
|
cache = &(g_array_index (view->coord_cache, struct coord_cache_entry, 0));
|
2005-07-08 01:46:01 +04:00
|
|
|
i = view_ccache_find (view, cache, coord, sorter);
|
2005-05-26 13:08:54 +04:00
|
|
|
/* 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;
|
2005-06-07 11:06:48 +04:00
|
|
|
nroff_state = NROFF_START;
|
2005-08-15 15:49:30 +04:00
|
|
|
for (; current.cc_offset < limit; current = next) {
|
2005-06-07 11:06:48 +04:00
|
|
|
int c;
|
2005-05-26 13:08:54 +04:00
|
|
|
|
|
|
|
if ((c = get_byte (view, current.cc_offset)) == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!coord_cache_entry_less (¤t, coord, sorter, view->text_nroff_mode)) {
|
|
|
|
if (lookup_what == CCACHE_OFFSET
|
|
|
|
&& view->text_nroff_mode
|
2005-06-07 11:06:48 +04:00
|
|
|
&& nroff_state != NROFF_START) {
|
2005-05-26 13:08:54 +04:00
|
|
|
/* don't break here */
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-15 15:49:30 +04:00
|
|
|
/* 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. */
|
2005-05-26 13:08:54 +04:00
|
|
|
if (c == '\r') {
|
2005-08-15 15:49:30 +04:00
|
|
|
next.cc_column = current.cc_column;
|
|
|
|
next.cc_nroff_column = current.cc_nroff_column;
|
|
|
|
|
2005-06-07 11:06:48 +04:00
|
|
|
} else if (nroff_state == NROFF_BACKSPACE) {
|
2005-08-15 15:49:30 +04:00
|
|
|
next.cc_nroff_column = current.cc_nroff_column - 1;
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
} else if (c == '\t') {
|
2005-08-15 15:49:30 +04:00
|
|
|
next.cc_column = offset_rounddown (current.cc_column, 8) + 8;
|
|
|
|
next.cc_nroff_column =
|
2005-05-26 13:08:54 +04:00
|
|
|
offset_rounddown (current.cc_nroff_column, 8) + 8;
|
2005-08-15 15:49:30 +04:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
} else if (c == '\n') {
|
2005-08-15 15:49:30 +04:00
|
|
|
next.cc_line = current.cc_line + 1;
|
|
|
|
next.cc_column = 0;
|
|
|
|
next.cc_nroff_column = 0;
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
} else {
|
2005-08-15 15:49:30 +04:00
|
|
|
/* Use all default values from above */
|
2005-05-26 13:08:54 +04:00
|
|
|
}
|
2005-06-07 11:06:48 +04:00
|
|
|
|
|
|
|
switch (nroff_state) {
|
|
|
|
case NROFF_START:
|
|
|
|
case NROFF_CONTINUATION:
|
2005-08-15 15:49:30 +04:00
|
|
|
if (is_nroff_sequence (view, current.cc_offset))
|
2005-06-07 11:06:48 +04:00
|
|
|
nroff_state = NROFF_BACKSPACE;
|
|
|
|
else
|
|
|
|
nroff_state = NROFF_START;
|
|
|
|
break;
|
|
|
|
case NROFF_BACKSPACE:
|
2005-07-03 19:31:55 +04:00
|
|
|
nroff_state = NROFF_CONTINUATION;
|
2005-06-07 11:06:48 +04:00
|
|
|
break;
|
|
|
|
}
|
2005-08-15 15:49:30 +04:00
|
|
|
|
2005-08-15 22:58:18 +04:00
|
|
|
/* 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. */
|
2005-08-15 15:49:30 +04:00
|
|
|
if (nroff_state == NROFF_START && c != '\r')
|
|
|
|
entry = next;
|
2005-05-26 13:08:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (i + 1 == view->coord_cache->len && entry.cc_offset != cache[i].cc_offset) {
|
|
|
|
g_array_append_val (view->coord_cache, entry);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_coord_to_offset (WView *view, offset_type *ret_offset,
|
|
|
|
offset_type line, offset_type column)
|
|
|
|
{
|
|
|
|
struct coord_cache_entry coord;
|
|
|
|
|
|
|
|
coord.cc_line = line;
|
|
|
|
coord.cc_column = column;
|
|
|
|
coord.cc_nroff_column = column;
|
|
|
|
view_ccache_lookup (view, &coord, CCACHE_OFFSET);
|
|
|
|
*ret_offset = coord.cc_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_offset_to_coord (WView *view, offset_type *ret_line,
|
|
|
|
offset_type *ret_column, offset_type offset)
|
|
|
|
{
|
|
|
|
struct coord_cache_entry coord;
|
|
|
|
|
|
|
|
coord.cc_offset = offset;
|
|
|
|
view_ccache_lookup (view, &coord, CCACHE_LINECOL);
|
|
|
|
*ret_line = coord.cc_line;
|
|
|
|
*ret_column = (view->text_nroff_mode)
|
|
|
|
? coord.cc_nroff_column
|
|
|
|
: coord.cc_column;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ Cursor Movement }}} */
|
|
|
|
|
|
|
|
/*
|
|
|
|
The following variables have to do with the current position and are
|
|
|
|
updated by the cursor movement functions.
|
|
|
|
|
|
|
|
In all viewer modes, dpy_topleft marks the offset of the top-left
|
|
|
|
corner on the screen. In hex mode, hex_cursor is the offset of the
|
|
|
|
cursor. In non-wrapping text mode, dpy_text_column is the number of
|
2005-06-06 03:43:49 +04:00
|
|
|
columns that are hidden on the left side on the screen.
|
2005-05-26 13:08:54 +04:00
|
|
|
|
|
|
|
In hex mode, dpy_topleft is updated by the view_fix_cursor_position()
|
|
|
|
function in order to keep the other functions simple. In text
|
|
|
|
non-wrap mode dpy_topleft and dpy_text_column are normalized such
|
|
|
|
that dpy_text_column < view_get_datacolumns().
|
|
|
|
*/
|
|
|
|
|
2005-05-26 13:22:51 +04:00
|
|
|
/* prototypes for functions used by view_moveto_bottom() */
|
|
|
|
static void view_move_up (WView *, offset_type);
|
|
|
|
static void view_moveto_bol (WView *);
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
static void
|
|
|
|
view_fix_cursor_position (WView *view)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
|
|
|
const offset_type bytes = view->bytes_per_line;
|
2005-07-06 23:12:25 +04:00
|
|
|
const offset_type displaysize = view->data_area.height * bytes;
|
2005-05-26 13:08:54 +04:00
|
|
|
const offset_type cursor = view->hex_cursor;
|
|
|
|
offset_type topleft = view->dpy_topleft;
|
|
|
|
|
|
|
|
if (topleft + displaysize <= cursor)
|
|
|
|
topleft = offset_rounddown (cursor, bytes)
|
2005-07-03 19:31:55 +04:00
|
|
|
- (displaysize - bytes);
|
2005-05-26 13:08:54 +04:00
|
|
|
if (cursor < topleft)
|
|
|
|
topleft = offset_rounddown (cursor, bytes);
|
|
|
|
view->dpy_topleft = topleft;
|
|
|
|
} else if (view->text_wrap_mode) {
|
|
|
|
offset_type line, col, columns;
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
columns = view->data_area.width;
|
2005-05-26 13:08:54 +04:00
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft + view->dpy_text_column);
|
2005-07-02 00:48:29 +04:00
|
|
|
if (columns != 0)
|
|
|
|
col = offset_rounddown (col, columns);
|
2005-05-26 13:08:54 +04:00
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, col);
|
|
|
|
view->dpy_text_column = 0;
|
|
|
|
} else {
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_movement_fixups (WView *view, gboolean reset_search)
|
|
|
|
{
|
|
|
|
view_fix_cursor_position (view);
|
|
|
|
if (reset_search) {
|
|
|
|
view->search_start = view->dpy_topleft;
|
|
|
|
view->found_len = 0;
|
|
|
|
}
|
|
|
|
view->dirty++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_moveto_top (WView *view)
|
|
|
|
{
|
|
|
|
view->dpy_topleft = 0;
|
|
|
|
if (view->hex_mode) {
|
|
|
|
view->hex_cursor = 0;
|
|
|
|
} else if (view->text_wrap_mode) {
|
|
|
|
/* nothing to do */
|
|
|
|
} else {
|
|
|
|
view->dpy_text_column = 0;
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_moveto_bottom (WView *view)
|
|
|
|
{
|
|
|
|
offset_type datalines, lines_up, filesize, last_offset;
|
|
|
|
|
|
|
|
if (view->growbuf_in_use)
|
|
|
|
view_growbuf_read_until (view, OFFSETTYPE_MAX);
|
|
|
|
|
|
|
|
filesize = view_get_filesize (view);
|
2005-07-06 23:12:25 +04:00
|
|
|
last_offset = offset_doz(filesize, 1);
|
|
|
|
datalines = view->data_area.height;
|
|
|
|
lines_up = offset_doz(datalines, 1);
|
2005-05-26 13:08:54 +04:00
|
|
|
|
|
|
|
if (view->hex_mode) {
|
|
|
|
view->hex_cursor = filesize;
|
|
|
|
view_move_up (view, lines_up);
|
|
|
|
view->hex_cursor = last_offset;
|
|
|
|
} else {
|
|
|
|
view->dpy_topleft = last_offset;
|
|
|
|
view_moveto_bol (view);
|
|
|
|
view_move_up (view, lines_up);
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_moveto_bol (WView *view)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
|
|
|
view->hex_cursor -= view->hex_cursor % view->bytes_per_line;
|
|
|
|
} else if (view->text_wrap_mode) {
|
|
|
|
/* do nothing */
|
|
|
|
} else {
|
|
|
|
offset_type line, column;
|
|
|
|
view_offset_to_coord (view, &line, &column, view->dpy_topleft);
|
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, 0);
|
|
|
|
view->dpy_text_column = 0;
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_moveto_eol (WView *view)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
|
|
|
offset_type filesize, bol;
|
|
|
|
|
|
|
|
bol = offset_rounddown (view->hex_cursor, view->bytes_per_line);
|
|
|
|
if (get_byte_indexed (view, bol, view->bytes_per_line - 1) != -1) {
|
|
|
|
view->hex_cursor = bol + view->bytes_per_line - 1;
|
|
|
|
} else {
|
|
|
|
filesize = view_get_filesize (view);
|
2005-07-06 23:12:25 +04:00
|
|
|
view->hex_cursor = offset_doz(filesize, 1);
|
2005-05-26 13:08:54 +04:00
|
|
|
}
|
|
|
|
} else if (view->text_wrap_mode) {
|
|
|
|
/* nothing to do */
|
|
|
|
} else {
|
|
|
|
offset_type line, col;
|
|
|
|
|
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, OFFSETTYPE_MAX);
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_moveto_offset (WView *view, offset_type offset)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
|
|
|
view->hex_cursor = offset;
|
|
|
|
view->dpy_topleft = offset - offset % view->bytes_per_line;
|
|
|
|
} else {
|
|
|
|
view->dpy_topleft = offset;
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_moveto (WView *view, offset_type line, offset_type col)
|
|
|
|
{
|
|
|
|
offset_type offset;
|
|
|
|
|
|
|
|
view_coord_to_offset (view, &offset, line, col);
|
|
|
|
view_moveto_offset (view, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_move_up (WView *view, offset_type lines)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
2005-06-14 17:34:41 +04:00
|
|
|
offset_type bytes = lines * view->bytes_per_line;
|
|
|
|
if (view->hex_cursor >= bytes) {
|
|
|
|
view->hex_cursor -= bytes;
|
2005-07-12 10:04:38 +04:00
|
|
|
view->dpy_topleft = offset_doz (view->dpy_topleft, bytes);
|
2005-05-26 13:08:54 +04:00
|
|
|
} else {
|
|
|
|
view->hex_cursor %= view->bytes_per_line;
|
|
|
|
}
|
|
|
|
} else if (view->text_wrap_mode) {
|
2005-07-06 23:12:25 +04:00
|
|
|
const screen_dimen width = view->data_area.width;
|
2005-05-26 13:08:54 +04:00
|
|
|
offset_type i, col, line, linestart;
|
|
|
|
|
|
|
|
for (i = 0; i < lines; i++) {
|
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
|
|
|
if (col >= width) {
|
|
|
|
col -= width;
|
|
|
|
} else if (line >= 1) {
|
|
|
|
view_coord_to_offset (view, &linestart, line, 0);
|
|
|
|
view_offset_to_coord (view, &line, &col, linestart - 1);
|
2005-06-07 11:37:00 +04:00
|
|
|
|
|
|
|
/* 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;
|
2005-05-26 13:08:54 +04:00
|
|
|
} else {
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, col);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
offset_type line, column;
|
|
|
|
|
|
|
|
view_offset_to_coord (view, &line, &column, view->dpy_topleft);
|
2005-07-06 23:12:25 +04:00
|
|
|
line = offset_doz(line, lines);
|
2005-05-26 13:08:54 +04:00
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, column);
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, (lines != 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_move_down (WView *view, offset_type lines)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
|
|
|
offset_type i, limit, last_byte;
|
|
|
|
|
|
|
|
last_byte = view_get_filesize (view);
|
|
|
|
if (last_byte >= (offset_type) 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_topleft += view->bytes_per_line;
|
|
|
|
}
|
2005-07-11 11:26:31 +04:00
|
|
|
} else if (view->text_wrap_mode) {
|
2005-05-26 13:08:54 +04:00
|
|
|
offset_type line, col, i;
|
|
|
|
|
2005-07-11 11:26:31 +04:00
|
|
|
for (i = 0; i < lines; i++) {
|
|
|
|
offset_type new_offset, chk_line, chk_col;
|
2005-06-07 11:37:00 +04:00
|
|
|
|
2005-07-11 11:26:31 +04:00
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
|
|
|
col += view->data_area.width;
|
|
|
|
view_coord_to_offset (view, &new_offset, line, col);
|
2005-06-07 11:37:00 +04:00
|
|
|
|
2005-07-11 11:26:31 +04:00
|
|
|
/* skip to the next line if the only thing that would be
|
|
|
|
* displayed is the newline character. */
|
|
|
|
view_offset_to_coord (view, &chk_line, &chk_col, new_offset);
|
|
|
|
if (chk_line == line && chk_col == col
|
|
|
|
&& get_byte (view, new_offset) == '\n')
|
|
|
|
new_offset++;
|
2005-06-07 11:37:00 +04:00
|
|
|
|
2005-07-11 11:26:31 +04:00
|
|
|
view->dpy_topleft = new_offset;
|
2005-05-26 13:08:54 +04:00
|
|
|
}
|
2005-07-11 11:26:31 +04:00
|
|
|
} else {
|
|
|
|
offset_type line, col;
|
|
|
|
|
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
|
|
|
line += lines;
|
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, col);
|
2005-05-26 13:08:54 +04:00
|
|
|
}
|
|
|
|
view_movement_fixups (view, (lines != 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_move_left (WView *view, offset_type 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;
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_move_right (WView *view, offset_type columns)
|
|
|
|
{
|
|
|
|
if (view->hex_mode) {
|
|
|
|
assert (columns == 1);
|
|
|
|
if (view->hexview_in_text || view->hexedit_lownibble) {
|
|
|
|
if (get_byte_indexed (view, view->hex_cursor, 1) != -1)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
view_movement_fixups (view, FALSE);
|
|
|
|
}
|
|
|
|
|
2005-05-26 14:17:38 +04:00
|
|
|
/* {{{ Miscellaneous functions }}} */
|
2005-05-26 13:08:54 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Both views */
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
view_done (WView *view)
|
|
|
|
{
|
2005-07-18 12:47:45 +04:00
|
|
|
if (mcview_remember_file_position && view->filename != NULL) {
|
2005-07-23 12:20:58 +04:00
|
|
|
char *canon_fname;
|
2005-07-18 12:47:45 +04:00
|
|
|
offset_type line, col;
|
2005-07-23 12:20:58 +04:00
|
|
|
|
|
|
|
canon_fname = vfs_canon (view->filename);
|
2005-07-18 12:47:45 +04:00
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
2005-07-23 12:20:58 +04:00
|
|
|
save_file_position (canon_fname, line + 1, col);
|
|
|
|
g_free (canon_fname);
|
2005-07-18 12:47:45 +04:00
|
|
|
}
|
2005-04-14 12:00:14 +04:00
|
|
|
view_close_datasource (view);
|
2005-05-26 13:08:54 +04:00
|
|
|
if (view->coord_cache) {
|
|
|
|
g_array_free (view->coord_cache, TRUE), view->coord_cache = NULL;
|
|
|
|
}
|
2005-04-14 12:00:14 +04:00
|
|
|
g_free (view->filename), view->filename = NULL;
|
|
|
|
g_free (view->command), view->command = NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
default_hex_mode = view->hex_mode;
|
2005-04-14 15:06:12 +04:00
|
|
|
default_nroff_flag = view->text_nroff_mode;
|
2005-04-14 15:12:01 +04:00
|
|
|
default_magic_flag = view->magic_mode;
|
2005-04-14 15:14:42 +04:00
|
|
|
global_wrap_mode = view->text_wrap_mode;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2005-06-28 16:13:37 +04:00
|
|
|
static void
|
|
|
|
view_show_error (WView *view, const char *msg)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-06-28 16:13:37 +04:00
|
|
|
view_close_datasource (view);
|
|
|
|
if (view_is_in_panel (view)) {
|
2005-04-25 12:50:59 +04:00
|
|
|
view_set_datasource_string (view, msg);
|
2005-06-28 16:13:37 +04:00
|
|
|
} else {
|
|
|
|
message (1, MSG_ERROR, "%s", msg);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-28 16:13:37 +04:00
|
|
|
static gboolean
|
2005-04-25 03:47:27 +04:00
|
|
|
view_load_command_output (WView *view, const char *command)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-04-25 03:47:27 +04:00
|
|
|
FILE *fp;
|
2002-09-08 19:22:28 +04:00
|
|
|
|
2005-04-07 15:23:53 +04:00
|
|
|
view_close_datasource (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
open_error_pipe ();
|
|
|
|
if ((fp = popen (command, "r")) == NULL) {
|
|
|
|
/* Avoid two messages. Message from stderr has priority. */
|
2005-07-14 01:30:28 +04:00
|
|
|
display (view);
|
2005-07-12 10:04:38 +04:00
|
|
|
if (!close_error_pipe (view_is_in_panel (view) ? -1 : 1, NULL))
|
|
|
|
view_show_error (view, _(" Cannot spawn child process "));
|
|
|
|
return FALSE;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
/* First, check if filter produced any output */
|
|
|
|
view_set_datasource_stdio_pipe (view, fp);
|
|
|
|
if (get_byte (view, 0) == -1) {
|
|
|
|
view_close_datasource (view);
|
2005-04-07 15:23:53 +04:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
/* Avoid two messages. Message from stderr has priority. */
|
2005-07-14 01:30:28 +04:00
|
|
|
display (view);
|
2005-07-12 10:04:38 +04:00
|
|
|
if (!close_error_pipe (view_is_in_panel (view) ? -1 : 1, NULL))
|
|
|
|
view_show_error (view, _("Empty output from child filter"));
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-06-28 16:13:37 +04:00
|
|
|
return TRUE;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2005-04-17 13:35:41 +04:00
|
|
|
gboolean
|
2005-07-12 11:01:47 +04:00
|
|
|
view_load (WView *view, const char *command, const char *file,
|
2005-04-14 12:00:14 +04:00
|
|
|
int start_line)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
1998-11-03 00:47:06 +03:00
|
|
|
int i, type;
|
2001-11-14 23:15:36 +03:00
|
|
|
int fd = -1;
|
2001-10-18 10:23:02 +04:00
|
|
|
char tmp[BUF_MEDIUM];
|
2004-12-02 20:13:39 +03:00
|
|
|
struct stat st;
|
2005-06-28 16:13:37 +04:00
|
|
|
gboolean retval = FALSE;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-01 02:58:52 +04:00
|
|
|
assert (view->bytes_per_line != 0);
|
2005-04-14 12:00:14 +04:00
|
|
|
view_done (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Set up the state */
|
2005-04-07 15:23:53 +04:00
|
|
|
view_set_datasource_none (view);
|
2005-07-12 11:01:47 +04:00
|
|
|
view->filename = g_strdup (file);
|
1998-02-27 07:54:42 +03:00
|
|
|
view->command = 0;
|
|
|
|
|
|
|
|
/* Clear the markers */
|
|
|
|
view->marker = 0;
|
|
|
|
for (i = 0; i < 10; i++)
|
2002-10-31 01:48:59 +03:00
|
|
|
view->marks[i] = 0;
|
|
|
|
|
2005-04-16 17:45:16 +04:00
|
|
|
if (!view_is_in_panel (view)) {
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_text_column = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
1998-11-03 00:47:06 +03:00
|
|
|
|
2005-07-12 11:01:47 +04:00
|
|
|
if (command && (view->magic_mode || file[0] == '\0')) {
|
|
|
|
retval = view_load_command_output (view, command);
|
|
|
|
} else if (file[0]) {
|
2002-12-16 06:43:49 +03:00
|
|
|
/* Open the file */
|
2005-07-12 11:01:47 +04:00
|
|
|
if ((fd = mc_open (file, O_RDONLY | O_NONBLOCK)) == -1) {
|
2002-12-16 06:43:49 +03:00
|
|
|
g_snprintf (tmp, sizeof (tmp), _(" Cannot open \"%s\"\n %s "),
|
2005-07-12 11:01:47 +04:00
|
|
|
file, unix_error_string (errno));
|
2005-06-28 16:13:37 +04:00
|
|
|
view_show_error (view, tmp);
|
2002-12-16 06:43:49 +03:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2001-11-14 23:15:36 +03:00
|
|
|
/* Make sure we are working with a regular file */
|
2004-12-02 20:13:39 +03:00
|
|
|
if (mc_fstat (fd, &st) == -1) {
|
2002-12-16 06:43:49 +03:00
|
|
|
mc_close (fd);
|
2001-11-14 23:15:36 +03:00
|
|
|
g_snprintf (tmp, sizeof (tmp), _(" Cannot stat \"%s\"\n %s "),
|
2005-07-12 11:01:47 +04:00
|
|
|
file, unix_error_string (errno));
|
2005-06-28 16:13:37 +04:00
|
|
|
view_show_error (view, tmp);
|
2001-11-14 23:15:36 +03:00
|
|
|
goto finish;
|
|
|
|
}
|
2001-10-18 10:23:02 +04:00
|
|
|
|
2004-12-02 20:13:39 +03:00
|
|
|
if (!S_ISREG (st.st_mode)) {
|
2002-12-16 06:43:49 +03:00
|
|
|
mc_close (fd);
|
2005-06-28 16:13:37 +04:00
|
|
|
view_show_error (view, _(" Cannot view: not a regular file "));
|
2001-11-14 23:15:36 +03:00
|
|
|
goto finish;
|
|
|
|
}
|
1999-04-16 09:53:46 +04:00
|
|
|
|
2005-04-07 15:23:53 +04:00
|
|
|
if (st.st_size == 0 || mc_lseek (fd, 0, SEEK_SET) == -1) {
|
|
|
|
/* Must be one of those nice files that grow (/proc) */
|
|
|
|
view_set_datasource_vfs_pipe (view, fd);
|
|
|
|
} else {
|
|
|
|
type = get_compression_type (fd);
|
2002-07-03 01:09:25 +04:00
|
|
|
|
2005-04-14 15:12:01 +04:00
|
|
|
if (view->magic_mode && (type != COMPRESSION_NONE)) {
|
2005-04-07 15:23:53 +04:00
|
|
|
g_free (view->filename);
|
2005-07-12 11:01:47 +04:00
|
|
|
view->filename = g_strconcat (file, decompress_extension (type), (char *) NULL);
|
2005-04-07 15:23:53 +04:00
|
|
|
}
|
|
|
|
view_set_datasource_file (view, fd, &st);
|
2001-11-14 23:15:36 +03:00
|
|
|
}
|
2005-06-28 16:13:37 +04:00
|
|
|
retval = TRUE;
|
2002-05-27 20:20:35 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
finish:
|
2005-07-12 11:01:47 +04:00
|
|
|
view->command = g_strdup (command);
|
2005-05-26 13:08:54 +04:00
|
|
|
view->dpy_topleft = 0;
|
|
|
|
view->search_start = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
view->found_len = 0;
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_text_column = 0;
|
2002-10-31 01:48:59 +03:00
|
|
|
view->last_search = 0; /* Start a new search */
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-01 02:58:52 +04:00
|
|
|
assert (view->bytes_per_line != 0);
|
2005-07-18 12:47:45 +04:00
|
|
|
if (mcview_remember_file_position && file != NULL && start_line == 0) {
|
|
|
|
long line, col;
|
2005-07-23 12:20:58 +04:00
|
|
|
char *canon_fname;
|
|
|
|
|
|
|
|
canon_fname = vfs_canon (file);
|
2005-07-18 12:47:45 +04:00
|
|
|
load_file_position (file, &line, &col);
|
2005-07-23 12:20:58 +04:00
|
|
|
g_free (canon_fname);
|
2005-07-18 12:47:45 +04:00
|
|
|
view_moveto (view, offset_doz(line, 1), col);
|
|
|
|
} else if (start_line > 0) {
|
|
|
|
view_moveto (view, start_line - 1, 0);
|
|
|
|
}
|
I improved the movement keys of the internal viewer a little bit.
Now in wrap mode the End key and cursor up key behave much better
(e.g. when viewing binary files with lots of wrapped lines).
It's not perfekt but it's better than it used to be.
Tue Apr 28 06:52:24 1998 Norbert Warmuth <k3190@fh-sw.de>
* gnome/gcmd.c (gnome_open_terminal): Changed my_system(1,...) to
my_system(EXECUTE_AS_SHELL,...)
Tue Apr 28 06:06:03 1998 Norbert Warmuth <k3190@fh-sw.de>
* vfs/extfs.c (extfs_open, extfs_close): Changed my_system(1,...)
to my_system(EXECUTE_AS_SHELL,...), this fixes the broken copyin and
copyout in 4.1.32.
Tue Apr 28 06:11:08 1998 Norbert Warmuth <k3190@fh-sw.de>
* view.c (toggle_wrap_mode, toggle_hex_mode): Force recalculation
of bottom_first (we mustn't use an already calculated and cached
value because it is invalid for the new mode and the End key would
not move to the end of the file).
* configure.in: Renamed the option `--with-our-slang' to
`--with-included-slang' (this one looks better because we also
have an `--with-included-gettext').
Make the option `--with-ext2undel' recognice a given path.
* cmd.c (view_file_at_line): In plain view (F13) set the default
magic flag to zero in order to view the file content unprocessed
(esp. don't uncompress files if they are compressed). The
view_simple_cmd got broken when the default magic flag in view.c
was changed from 0 to 1.
* view.c (do_view_init, goto_line): Set wrap mode temporary off
to make goto line number work, i.e. `line number' now always means
line number in file and not line number on screen (in wrap mode
one long line wrapped once is displayed in two lines on the screen).
That's important when the viewer is invoked from the find file
dialog to display even in wrap mode approxiamtly the part of the
file where we found the content we searched for.
(move_forward2): In wrap mode lines were sometimes counted wrong
causing cursor up to move more than one line.
(move_backward2): Fixed the movement in wrap mode.
(change_viewer): Always re-init viewer when we have a filename,
i. e. if the viewer is invoked with simple_view_cmd then we can switch
with the F8 key between unprocessed file content und uncompressed
file content.
(view_init): re-init view also when magic flag was altered
1998-04-28 18:19:48 +04:00
|
|
|
|
2005-04-20 00:33:51 +04:00
|
|
|
view->hexedit_lownibble = FALSE;
|
2005-04-14 14:59:02 +04:00
|
|
|
view->hexview_in_text = FALSE;
|
1998-02-27 07:54:42 +03:00
|
|
|
view->change_list = NULL;
|
|
|
|
|
2005-06-28 16:13:37 +04:00
|
|
|
return retval;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2005-05-26 14:40:10 +04:00
|
|
|
/* {{{ Display management }}} */
|
|
|
|
|
2005-01-26 01:40:50 +03:00
|
|
|
static void
|
2002-10-07 22:09:50 +04:00
|
|
|
view_update_bytes_per_line (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
const screen_dimen cols = view->data_area.width;
|
2005-07-11 11:39:04 +04:00
|
|
|
int bytes;
|
2000-11-20 20:25:43 +03:00
|
|
|
|
2005-07-07 21:09:59 +04:00
|
|
|
if (cols < 8)
|
2005-07-11 11:39:04 +04:00
|
|
|
bytes = 1;
|
2005-07-07 21:09:59 +04:00
|
|
|
else if (cols < 80)
|
2005-07-11 11:39:04 +04:00
|
|
|
bytes = ((cols - 8) / 17) * 4;
|
2002-10-07 22:09:50 +04:00
|
|
|
else
|
2005-07-11 11:39:04 +04:00
|
|
|
bytes = ((cols - 8) / 18) * 4;
|
2002-10-07 22:09:50 +04:00
|
|
|
|
2005-07-11 11:39:04 +04:00
|
|
|
if (bytes == 0)
|
|
|
|
bytes = 1; /* To avoid division by 0 */
|
2002-10-07 22:09:50 +04:00
|
|
|
|
2005-07-11 11:39:04 +04:00
|
|
|
view->bytes_per_line = bytes;
|
1998-02-27 07:54:42 +03:00
|
|
|
view->dirty = max_dirt_limit + 1; /* To force refresh */
|
1999-04-06 23:00:16 +04:00
|
|
|
}
|
|
|
|
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
2005-04-16 17:45:16 +04:00
|
|
|
view_percent (WView *view, offset_type p)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-06 23:36:59 +04:00
|
|
|
const screen_dimen right = view->status_area.left + view->status_area.width;
|
2005-07-07 21:49:01 +04:00
|
|
|
const screen_dimen height = view->status_area.height;
|
1998-02-27 07:54:42 +03:00
|
|
|
int percent;
|
2005-04-14 01:09:00 +04:00
|
|
|
offset_type filesize;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-07 21:49:01 +04:00
|
|
|
if (height < 1 || right < 4)
|
2005-07-06 23:36:59 +04:00
|
|
|
return;
|
2005-06-14 18:13:11 +04:00
|
|
|
if (view_may_still_grow (view))
|
2005-04-14 01:09:00 +04:00
|
|
|
return;
|
2005-06-14 18:13:11 +04:00
|
|
|
filesize = view_get_filesize (view);
|
2005-04-14 01:09:00 +04:00
|
|
|
|
2005-04-25 12:47:22 +04:00
|
|
|
if (filesize == 0 || view->dpy_complete)
|
2005-07-03 19:31:55 +04:00
|
|
|
percent = 100;
|
2004-12-02 20:13:39 +03:00
|
|
|
else if (p > (INT_MAX / 100))
|
2005-07-03 19:31:55 +04:00
|
|
|
percent = p / (filesize / 100);
|
2004-12-02 20:13:39 +03:00
|
|
|
else
|
2005-07-03 19:31:55 +04:00
|
|
|
percent = p * 100 / filesize;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-06 23:36:59 +04:00
|
|
|
widget_move (view, view->dpy_frame_size, right - 4);
|
2005-04-26 19:06:38 +04:00
|
|
|
printw (str_unconst ("%3d%%"), percent);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
2005-07-07 20:59:31 +04:00
|
|
|
view_display_status (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
const screen_dimen top = view->status_area.top;
|
|
|
|
const screen_dimen left = view->status_area.left;
|
|
|
|
const screen_dimen width = view->status_area.width;
|
2005-07-07 21:49:01 +04:00
|
|
|
const screen_dimen height = view->status_area.height;
|
|
|
|
const char *file_label, *file_name;
|
2005-07-06 23:12:25 +04:00
|
|
|
screen_dimen file_label_width;
|
1998-02-27 07:54:42 +03:00
|
|
|
int i;
|
|
|
|
|
2005-07-07 21:49:01 +04:00
|
|
|
if (height < 1)
|
|
|
|
return;
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
attrset (SELECTED_COLOR);
|
2005-07-06 23:12:25 +04:00
|
|
|
widget_move (view, top, left);
|
|
|
|
hline (' ', width);
|
1999-04-06 23:00:16 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
file_label = _("File: %s");
|
|
|
|
file_label_width = strlen (file_label) - 2;
|
2005-07-07 21:49:01 +04:00
|
|
|
file_name = view->filename ? view->filename
|
|
|
|
: view->command ? view->command
|
|
|
|
: "";
|
1999-04-06 23:00:16 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
if (width < file_label_width + 6)
|
2005-07-07 21:49:01 +04:00
|
|
|
addstr ((char *) name_trunc (file_name, width));
|
2002-10-31 01:48:59 +03:00
|
|
|
else {
|
2005-07-06 23:12:25 +04:00
|
|
|
i = (width > 22 ? 22 : width) - file_label_width;
|
2005-07-07 21:49:01 +04:00
|
|
|
printw (str_unconst (file_label), name_trunc (file_name, i));
|
2005-07-06 23:12:25 +04:00
|
|
|
if (width > 46) {
|
|
|
|
widget_move (view, top, left + 24);
|
2005-04-16 18:25:52 +04:00
|
|
|
/* FIXME: the format strings need to be changed when offset_type changes */
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->hex_mode)
|
2005-05-21 14:23:57 +04:00
|
|
|
printw (str_unconst (_("Offset 0x%08lx")), view->hex_cursor);
|
2005-05-26 13:08:54 +04:00
|
|
|
else {
|
|
|
|
offset_type line, col;
|
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
|
|
|
printw (str_unconst (_("Line %lu Col %lu")),
|
|
|
|
(unsigned long) line + 1,
|
|
|
|
(unsigned long) (view->text_wrap_mode ? col : view->dpy_text_column));
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
}
|
2005-07-06 23:12:25 +04:00
|
|
|
if (width > 62) {
|
2005-04-14 01:09:00 +04:00
|
|
|
offset_type filesize;
|
2005-06-14 18:13:11 +04:00
|
|
|
filesize = view_get_filesize (view);
|
2005-07-06 23:12:25 +04:00
|
|
|
widget_move (view, top, left + 43);
|
2005-06-14 18:13:11 +04:00
|
|
|
if (!view_may_still_grow (view)) {
|
2005-04-20 02:16:25 +04:00
|
|
|
printw (str_unconst (_("%s bytes")), size_trunc (filesize));
|
2005-04-14 01:09:00 +04:00
|
|
|
} else {
|
2005-04-20 02:16:25 +04:00
|
|
|
printw (str_unconst (_(">= %s bytes")), size_trunc (filesize));
|
2005-04-14 01:09:00 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-07-06 23:12:25 +04:00
|
|
|
if (width > 26) {
|
2005-04-16 17:45:16 +04:00
|
|
|
view_percent (view, view->hex_mode
|
2005-05-21 14:23:57 +04:00
|
|
|
? view->hex_cursor
|
2005-05-21 14:17:35 +04:00
|
|
|
: view->dpy_topleft);
|
1999-05-03 22:57:48 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
attrset (SELECTED_COLOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2005-07-06 23:12:25 +04:00
|
|
|
view_display_clean (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
attrset (NORMAL_COLOR);
|
|
|
|
widget_erase ((Widget *) view);
|
2005-04-19 01:02:55 +04:00
|
|
|
if (view->dpy_frame_size != 0) {
|
2002-10-31 01:48:59 +03:00
|
|
|
draw_double_box (view->widget.parent, view->widget.y,
|
|
|
|
view->widget.x, view->widget.lines,
|
|
|
|
view->widget.cols);
|
2005-07-06 23:12:25 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
1998-03-12 06:29:45 +03:00
|
|
|
#define view_add_character(view,c) addch (c)
|
1998-12-02 08:18:20 +03:00
|
|
|
#define view_add_one_vline() one_vline()
|
1998-03-12 06:29:45 +03:00
|
|
|
#define view_add_string(view,s) addstr (s)
|
|
|
|
#define view_gotoyx(v,r,c) widget_move (v,r,c)
|
|
|
|
|
2002-08-19 00:18:04 +04:00
|
|
|
typedef enum {
|
|
|
|
MARK_NORMAL = 0,
|
|
|
|
MARK_SELECTED = 1,
|
|
|
|
MARK_CURSOR = 2,
|
|
|
|
MARK_CHANGED = 3
|
|
|
|
} mark_t;
|
|
|
|
|
2005-04-19 01:02:55 +04:00
|
|
|
static inline int
|
|
|
|
view_count_backspaces (WView *view, off_t offset)
|
2004-09-25 06:00:25 +04:00
|
|
|
{
|
|
|
|
int backspaces = 0;
|
2005-04-14 01:09:00 +04:00
|
|
|
while (offset >= 2 * backspaces
|
|
|
|
&& get_byte (view, offset - 2 * backspaces) == '\b')
|
2005-07-03 19:31:55 +04:00
|
|
|
backspaces++;
|
2004-09-25 06:00:25 +04:00
|
|
|
return backspaces;
|
|
|
|
}
|
|
|
|
|
2005-04-20 02:33:21 +04:00
|
|
|
static void
|
|
|
|
view_display_ruler (WView *view)
|
|
|
|
{
|
2005-07-11 12:14:44 +04:00
|
|
|
static const char ruler_chars[] = "|----*----";
|
2005-07-06 23:12:25 +04:00
|
|
|
const screen_dimen top = view->ruler_area.top;
|
|
|
|
const screen_dimen left = view->ruler_area.left;
|
|
|
|
const screen_dimen width = view->ruler_area.width;
|
2005-07-07 21:49:01 +04:00
|
|
|
const screen_dimen height = view->ruler_area.height;
|
2005-07-06 23:12:25 +04:00
|
|
|
const screen_dimen line_row = (ruler == RULER_TOP) ? 0 : 1;
|
|
|
|
const screen_dimen nums_row = (ruler == RULER_TOP) ? 1 : 0;
|
2005-04-20 02:33:21 +04:00
|
|
|
|
|
|
|
char r_buff[10];
|
|
|
|
offset_type cl;
|
2005-07-06 23:12:25 +04:00
|
|
|
screen_dimen c;
|
|
|
|
|
2005-07-07 21:49:01 +04:00
|
|
|
if (ruler == RULER_NONE || height < 1)
|
2005-07-06 23:12:25 +04:00
|
|
|
return;
|
2005-04-20 02:33:21 +04:00
|
|
|
|
|
|
|
attrset (MARKED_COLOR);
|
2005-07-06 23:12:25 +04:00
|
|
|
for (c = 0; c < width; c++) {
|
|
|
|
cl = view->dpy_text_column + c;
|
2005-07-07 21:49:01 +04:00
|
|
|
if (line_row < height) {
|
|
|
|
view_gotoyx (view, top + line_row, left + c);
|
|
|
|
view_add_character (view, ruler_chars[cl % 10]);
|
|
|
|
}
|
2005-04-20 02:33:21 +04:00
|
|
|
|
|
|
|
if ((cl != 0) && (cl % 10) == 0) {
|
2005-04-25 04:26:46 +04:00
|
|
|
g_snprintf (r_buff, sizeof (r_buff), "%"OFFSETTYPE_PRId, cl);
|
2005-07-07 21:49:01 +04:00
|
|
|
if (nums_row < height) {
|
|
|
|
widget_move (view, top + nums_row, left + c - 1);
|
|
|
|
view_add_string (view, r_buff);
|
|
|
|
}
|
2005-04-20 02:33:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
attrset (NORMAL_COLOR);
|
|
|
|
}
|
|
|
|
|
2005-06-28 17:02:09 +04:00
|
|
|
static void
|
2005-06-28 17:21:42 +04:00
|
|
|
view_display_hex (WView *view)
|
2005-07-11 12:14:44 +04:00
|
|
|
/* FIXME: prevent any screen overflows */
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
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 screen_dimen text_start = width - view->bytes_per_line;
|
|
|
|
const screen_dimen hex_start = 9;
|
|
|
|
|
|
|
|
screen_dimen row, col;
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type from;
|
1998-02-27 07:54:42 +03:00
|
|
|
int c;
|
2002-08-19 00:18:04 +04:00
|
|
|
mark_t boldflag = MARK_NORMAL;
|
1998-02-27 07:54:42 +03:00
|
|
|
struct hexedit_change_node *curr = view->change_list;
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
|
|
|
|
int bytes; /* Number of bytes already printed on the line */
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
view_display_clean (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Find the first displayable changed byte */
|
2005-07-06 23:12:25 +04:00
|
|
|
from = view->dpy_topleft;
|
2000-11-20 20:25:43 +03:00
|
|
|
while (curr && (curr->offset < from)) {
|
2002-07-26 21:17:41 +04:00
|
|
|
curr = curr->next;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
attrset (NORMAL_COLOR);
|
|
|
|
for (row = 0; get_byte (view, from) != -1 && row < height; row++) {
|
2005-06-28 17:21:42 +04:00
|
|
|
/* Print the hex offset */
|
|
|
|
attrset (MARKED_COLOR);
|
|
|
|
g_snprintf (hex_buff, sizeof (hex_buff), "%08"OFFSETTYPE_PRIX, from);
|
2005-07-06 23:12:25 +04:00
|
|
|
view_gotoyx (view, top + row, left);
|
2005-06-28 17:21:42 +04:00
|
|
|
view_add_string (view, hex_buff);
|
|
|
|
attrset (NORMAL_COLOR);
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
col = hex_start;
|
2005-06-28 17:21:42 +04:00
|
|
|
/* Each hex number is two digits */
|
2005-07-06 23:12:25 +04:00
|
|
|
hex_buff[2] = '\0';
|
2005-06-28 17:21:42 +04:00
|
|
|
for (bytes = 0;
|
|
|
|
bytes < view->bytes_per_line
|
|
|
|
&& (c = get_byte (view, from)) != -1;
|
|
|
|
bytes++, from++) {
|
|
|
|
/* Display and mark changed bytes */
|
|
|
|
if (curr && from == curr->offset) {
|
2005-07-03 19:31:55 +04:00
|
|
|
c = curr->value;
|
2005-06-28 17:21:42 +04:00
|
|
|
curr = curr->next;
|
|
|
|
boldflag = MARK_CHANGED;
|
|
|
|
attrset (VIEW_UNDERLINED_COLOR);
|
|
|
|
}
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
if (view->found_len && from >= view->search_start
|
|
|
|
&& from < view->search_start + view->found_len) {
|
|
|
|
boldflag = MARK_SELECTED;
|
|
|
|
attrset (MARKED_COLOR);
|
|
|
|
}
|
|
|
|
/* Display the navigation cursor */
|
|
|
|
if (from == view->hex_cursor) {
|
|
|
|
if (!view->hexview_in_text) {
|
|
|
|
view->cursor_row = row;
|
|
|
|
view->cursor_col = col;
|
2002-07-26 21:17:41 +04:00
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
boldflag = MARK_CURSOR;
|
|
|
|
attrset (view->hexview_in_text
|
|
|
|
? MARKED_SELECTED_COLOR
|
|
|
|
: VIEW_UNDERLINED_COLOR);
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
/* Print a hex number (sprintf is too slow) */
|
|
|
|
hex_buff[0] = hex_char[(c >> 4)];
|
|
|
|
hex_buff[1] = hex_char[c & 15];
|
2005-07-06 23:12:25 +04:00
|
|
|
view_gotoyx (view, top + row, left + col);
|
2005-06-28 17:21:42 +04:00
|
|
|
view_add_string (view, hex_buff);
|
|
|
|
col += 3;
|
|
|
|
/* Turn off the cursor or changed byte highlighting here */
|
|
|
|
if (boldflag == MARK_CURSOR || boldflag == MARK_CHANGED)
|
2005-07-03 19:31:55 +04:00
|
|
|
attrset (NORMAL_COLOR);
|
2005-06-28 17:21:42 +04:00
|
|
|
if ((bytes & 3) == 3 && bytes + 1 < view->bytes_per_line) {
|
|
|
|
/* Turn off the search highlighting */
|
|
|
|
if (boldflag == MARK_SELECTED
|
2005-07-06 23:12:25 +04:00
|
|
|
&& from == view->search_start + view->found_len - 1)
|
2002-08-14 11:41:01 +04:00
|
|
|
attrset (NORMAL_COLOR);
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
/* Hex numbers are printed in the groups of four */
|
|
|
|
/* Groups are separated by a vline */
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
view_gotoyx (view, top + row, left + col - 1);
|
2005-06-28 17:21:42 +04:00
|
|
|
view_add_character (view, ' ');
|
2005-07-06 23:12:25 +04:00
|
|
|
view_gotoyx (view, top + row, left + col);
|
|
|
|
if (view->data_area.width < 80)
|
2005-06-28 17:21:42 +04:00
|
|
|
col += 1;
|
|
|
|
else {
|
|
|
|
view_add_one_vline ();
|
|
|
|
col += 2;
|
2002-07-26 21:17:41 +04:00
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
|
2002-08-19 00:18:04 +04:00
|
|
|
if (boldflag != MARK_NORMAL
|
2005-07-06 23:12:25 +04:00
|
|
|
&& from == view->search_start + view->found_len - 1)
|
2005-06-28 17:21:42 +04:00
|
|
|
attrset (MARKED_COLOR);
|
|
|
|
}
|
|
|
|
if (boldflag != MARK_NORMAL
|
|
|
|
&& from < view->search_start + view->found_len - 1
|
|
|
|
&& bytes != view->bytes_per_line - 1) {
|
2005-07-06 23:12:25 +04:00
|
|
|
view_gotoyx (view, top + row, left + col);
|
2005-06-28 17:21:42 +04:00
|
|
|
view_add_character (view, ' ');
|
|
|
|
}
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
/* Print corresponding character on the text side */
|
2005-07-06 23:12:25 +04:00
|
|
|
view_gotoyx (view, top + row, left + text_start + bytes);
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
c = convert_to_display_c (c);
|
2001-06-06 02:49:15 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
if (!is_printable (c))
|
|
|
|
c = '.';
|
|
|
|
switch (boldflag) {
|
|
|
|
case MARK_NORMAL:
|
|
|
|
break;
|
|
|
|
case MARK_SELECTED:
|
|
|
|
attrset (MARKED_COLOR);
|
|
|
|
break;
|
|
|
|
case MARK_CURSOR:
|
|
|
|
if (view->hexview_in_text) {
|
|
|
|
/* Our side is active */
|
|
|
|
view->cursor_col = text_start + bytes;
|
|
|
|
view->cursor_row = row;
|
2002-08-19 00:18:04 +04:00
|
|
|
attrset (VIEW_UNDERLINED_COLOR);
|
2005-06-28 17:21:42 +04:00
|
|
|
} else {
|
|
|
|
/* Other side is active */
|
|
|
|
attrset (MARKED_SELECTED_COLOR);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
break;
|
|
|
|
case MARK_CHANGED:
|
|
|
|
attrset (VIEW_UNDERLINED_COLOR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
view_add_character (view, c);
|
2002-07-26 21:17:41 +04:00
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
if (boldflag != MARK_NORMAL) {
|
|
|
|
boldflag = MARK_NORMAL;
|
|
|
|
attrset (NORMAL_COLOR);
|
2002-07-26 21:17:41 +04:00
|
|
|
}
|
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
}
|
|
|
|
view_place_cursor (view);
|
|
|
|
view->dpy_complete = (get_byte (view, from) == -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_display_text (WView * view)
|
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
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;
|
2005-06-28 17:21:42 +04:00
|
|
|
offset_type from;
|
|
|
|
int c;
|
|
|
|
mark_t boldflag = MARK_NORMAL;
|
|
|
|
struct hexedit_change_node *curr = view->change_list;
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
view_display_clean (view);
|
|
|
|
view_display_ruler (view);
|
2005-06-28 17:21:42 +04:00
|
|
|
|
|
|
|
/* Find the first displayable changed byte */
|
2005-07-06 23:12:25 +04:00
|
|
|
from = view->dpy_topleft;
|
2005-06-28 17:21:42 +04:00
|
|
|
while (curr && (curr->offset < from)) {
|
|
|
|
curr = curr->next;
|
|
|
|
}
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
attrset (NORMAL_COLOR);
|
|
|
|
for (row = 0, col = 0; row < height && (c = get_byte (view, from)) != -1; from++) {
|
2005-06-28 17:21:42 +04:00
|
|
|
if (view->text_nroff_mode && c == '\b') {
|
|
|
|
int c_prev;
|
|
|
|
int c_next;
|
|
|
|
|
|
|
|
if ((c_next = get_byte_indexed (view, from, 1)) != -1
|
|
|
|
&& is_printable (c_next)
|
|
|
|
&& from >= 1
|
|
|
|
&& (c_prev = get_byte (view, from - 1)) != -1
|
|
|
|
&& is_printable (c_prev)
|
|
|
|
&& (c_prev == c_next || c_prev == '_'
|
|
|
|
|| (c_prev == '+' && c_next == 'o'))) {
|
2005-07-06 23:12:25 +04:00
|
|
|
if (col == 0) {
|
2005-07-07 22:06:57 +04:00
|
|
|
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;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
row--;
|
2005-07-06 23:12:25 +04:00
|
|
|
col = width;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
col--;
|
2002-08-19 00:18:04 +04:00
|
|
|
boldflag = MARK_SELECTED;
|
2005-06-28 17:21:42 +04:00
|
|
|
if (c_prev == '_' && (c_next != '_' || view_count_backspaces (view, from) == 1))
|
|
|
|
attrset (VIEW_UNDERLINED_COLOR);
|
|
|
|
else
|
|
|
|
attrset (MARKED_COLOR);
|
|
|
|
continue;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
}
|
2005-07-06 23:12:25 +04:00
|
|
|
if ((c == '\n') || (col >= width && view->text_wrap_mode)) {
|
|
|
|
col = 0;
|
2005-06-28 17:21:42 +04:00
|
|
|
row++;
|
2005-07-06 23:12:25 +04:00
|
|
|
if (c == '\n' || row >= height)
|
2005-06-28 17:21:42 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '\r')
|
|
|
|
continue;
|
|
|
|
if (c == '\t') {
|
2005-07-07 22:38:12 +04:00
|
|
|
offset_type line, column;
|
|
|
|
view_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;
|
|
|
|
}
|
2005-06-28 17:21:42 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-07-06 23:12:25 +04:00
|
|
|
if (view->found_len != 0
|
|
|
|
&& from >= view->search_start
|
2005-06-28 17:21:42 +04:00
|
|
|
&& from < view->search_start + view->found_len) {
|
|
|
|
boldflag = MARK_SELECTED;
|
|
|
|
attrset (SELECTED_COLOR);
|
|
|
|
}
|
2005-07-06 23:12:25 +04:00
|
|
|
if (col >= view->dpy_text_column
|
|
|
|
&& col - view->dpy_text_column < width) {
|
|
|
|
view_gotoyx (view, top + row, left + (col - view->dpy_text_column));
|
2005-06-28 17:21:42 +04:00
|
|
|
c = convert_to_display_c (c);
|
|
|
|
if (!is_printable (c))
|
|
|
|
c = '.';
|
|
|
|
view_add_character (view, c);
|
|
|
|
}
|
|
|
|
col++;
|
|
|
|
if (boldflag != MARK_NORMAL) {
|
|
|
|
boldflag = MARK_NORMAL;
|
|
|
|
attrset (NORMAL_COLOR);
|
2002-07-26 21:17:41 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-04-25 12:47:22 +04:00
|
|
|
view->dpy_complete = (get_byte (view, from) == -1);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2005-06-28 17:21:42 +04:00
|
|
|
/* Displays as much data from view->dpy_topleft as fits on the screen */
|
|
|
|
static void
|
|
|
|
display (WView *view)
|
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
view_compute_areas (view);
|
2005-06-28 17:21:42 +04:00
|
|
|
if (view->hex_mode) {
|
|
|
|
view_display_hex (view);
|
|
|
|
} else {
|
|
|
|
view_display_text (view);
|
|
|
|
}
|
2005-07-07 21:03:25 +04:00
|
|
|
view_display_status (view);
|
2005-06-28 17:21:42 +04:00
|
|
|
}
|
|
|
|
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
view_place_cursor (WView *view)
|
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
screen_dimen row, col;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
row = view->data_area.top + view->cursor_row;
|
|
|
|
col = view->data_area.left + view->cursor_col;
|
2005-04-20 00:33:51 +04:00
|
|
|
if (!view->hexview_in_text && view->hexedit_lownibble)
|
2005-07-06 23:12:25 +04:00
|
|
|
col++;
|
|
|
|
widget_move (&view->widget, row, col);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
static int dirt_limit = 1;
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->dirty > dirt_limit) {
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Too many updates skipped -> force a update */
|
|
|
|
display (view);
|
|
|
|
view->dirty = 0;
|
|
|
|
/* Raise the update skipping limit */
|
|
|
|
dirt_limit++;
|
|
|
|
if (dirt_limit > max_dirt_limit)
|
|
|
|
dirt_limit = max_dirt_limit;
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->dirty) {
|
|
|
|
if (is_idle ()) {
|
1998-02-27 07:54:42 +03:00
|
|
|
/* We have time to update the screen properly */
|
|
|
|
display (view);
|
|
|
|
view->dirty = 0;
|
|
|
|
if (dirt_limit > 1)
|
|
|
|
dirt_limit--;
|
|
|
|
} else {
|
|
|
|
/* We are busy -> skipping full update,
|
|
|
|
only the status line is updated */
|
2005-07-07 20:59:31 +04:00
|
|
|
view_display_status (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
/* Here we had a refresh, if fast scrolling does not work
|
|
|
|
restore the refresh, although this should not happen */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-26 14:40:10 +04:00
|
|
|
/* {{{ Hex editor }}} */
|
|
|
|
|
|
|
|
static void
|
|
|
|
enqueue_change (struct hexedit_change_node **head,
|
|
|
|
struct hexedit_change_node *node)
|
|
|
|
{
|
2005-07-11 12:17:38 +04:00
|
|
|
/* 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. */
|
2005-05-26 14:40:10 +04:00
|
|
|
struct hexedit_change_node **chnode = head;
|
|
|
|
|
|
|
|
while (*chnode != NULL && (*chnode)->offset < node->offset)
|
|
|
|
chnode = &((*chnode)->next);
|
|
|
|
|
|
|
|
node->next = *chnode;
|
|
|
|
*chnode = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static cb_ret_t
|
|
|
|
view_handle_editkey (WView *view, int key)
|
|
|
|
{
|
|
|
|
struct hexedit_change_node *node;
|
|
|
|
byte 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
|
|
|
|
byte_val = get_byte (view, view->hex_cursor);
|
|
|
|
|
|
|
|
if (view->hexedit_lownibble) {
|
|
|
|
byte_val = (byte_val & 0xf0) | (hexvalue);
|
|
|
|
} else {
|
|
|
|
byte_val = (byte_val & 0x0f) | (hexvalue << 4);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Text editing */
|
|
|
|
if (key < 256 && (is_printable (key) || (key == '\n')))
|
|
|
|
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;
|
|
|
|
enqueue_change (&view->change_list, node);
|
|
|
|
} else {
|
|
|
|
node->value = byte_val;
|
|
|
|
}
|
|
|
|
view->dirty++;
|
|
|
|
view_update (view);
|
|
|
|
view_move_right (view, 1);
|
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_change_list (WView *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++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
view_hexedit_save_changes (WView *view)
|
|
|
|
{
|
|
|
|
struct hexedit_change_node *curr, *next;
|
|
|
|
int fp, answer;
|
|
|
|
char *text, *error;
|
|
|
|
|
|
|
|
retry_save:
|
2005-07-12 11:22:49 +04:00
|
|
|
fp = mc_open (view->filename, O_WRONLY);
|
2005-05-26 14:40:10 +04:00
|
|
|
if (fp == -1)
|
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
for (curr = view->change_list; curr != NULL; curr = next) {
|
|
|
|
next = curr->next;
|
|
|
|
|
2005-07-12 11:22:49 +04:00
|
|
|
if (mc_lseek (fp, curr->offset, SEEK_SET) == -1
|
|
|
|
|| mc_write (fp, &(curr->value), 1) != 1)
|
2005-05-26 14:40:10 +04:00
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
/* delete the saved item from the change list */
|
|
|
|
view->change_list = next;
|
|
|
|
view->dirty++;
|
|
|
|
view_set_byte (view, curr->offset, curr->value);
|
|
|
|
g_free (curr);
|
|
|
|
}
|
|
|
|
|
2005-07-12 11:22:49 +04:00
|
|
|
if (mc_close (fp) == -1) {
|
2005-05-26 14:40:10 +04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
view_update (view);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
save_error:
|
|
|
|
error = g_strdup (strerror (errno));
|
|
|
|
text = g_strdup_printf (_(" Cannot save file: \n %s "), error);
|
|
|
|
g_free (error);
|
2005-07-12 11:22:49 +04:00
|
|
|
(void) mc_close (fp);
|
2005-05-26 14:40:10 +04:00
|
|
|
|
|
|
|
answer = query_dialog (_(" Save file "), text, D_ERROR,
|
|
|
|
2, _("&Retry"), _("&Cancel"));
|
|
|
|
g_free (text);
|
|
|
|
|
|
|
|
if (answer == 0)
|
|
|
|
goto retry_save;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ Miscellaneous functions }}} */
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
view_ok_to_quit (WView *view)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!view->change_list)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = query_dialog (_("Quit"),
|
|
|
|
_(" File was modified, Save with exit? "), D_NORMAL, 3,
|
|
|
|
_("&Cancel quit"), _("&Yes"), _("&No"));
|
|
|
|
|
|
|
|
switch (r) {
|
|
|
|
case 1:
|
|
|
|
return view_hexedit_save_changes (view);
|
|
|
|
case 2:
|
|
|
|
free_change_list (view);
|
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
static inline void
|
2004-08-16 08:16:55 +04:00
|
|
|
my_define (Dlg_head *h, int idx, const char *text, void (*fn) (WView *),
|
2002-11-13 02:33:15 +03:00
|
|
|
WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-02-08 12:53:51 +03:00
|
|
|
buttonbar_set_label_data (h, idx, text, (buttonbarfn) fn, view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Case insensitive search of text in data */
|
|
|
|
static int
|
|
|
|
icase_search_p (WView *view, char *text, char *data, int nothing)
|
|
|
|
{
|
2004-08-16 08:16:55 +04:00
|
|
|
const char *q;
|
2000-11-20 20:25:43 +03:00
|
|
|
int lng;
|
2004-08-16 08:16:55 +04:00
|
|
|
const int direction = view->direction;
|
2003-03-19 16:39:48 +03:00
|
|
|
|
2005-02-08 01:09:44 +03:00
|
|
|
(void) nothing;
|
|
|
|
|
2003-03-19 16:39:48 +03:00
|
|
|
/* If we are searching backwards, reverse the string */
|
2003-03-21 19:01:50 +03:00
|
|
|
if (direction == -1) {
|
2003-03-19 16:39:48 +03:00
|
|
|
g_strreverse (text);
|
2003-03-21 19:01:50 +03:00
|
|
|
g_strreverse (data);
|
|
|
|
}
|
2003-03-19 16:39:48 +03:00
|
|
|
|
|
|
|
q = _icase_search (text, data, &lng);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2003-03-21 19:01:50 +03:00
|
|
|
if (direction == -1) {
|
2003-03-19 16:39:48 +03:00
|
|
|
g_strreverse (text);
|
2003-03-21 19:01:50 +03:00
|
|
|
g_strreverse (data);
|
|
|
|
}
|
2003-03-19 16:39:48 +03:00
|
|
|
|
|
|
|
if (q != 0) {
|
|
|
|
if (direction > 0)
|
|
|
|
view->search_start = q - data - lng;
|
|
|
|
else
|
|
|
|
view->search_start = strlen (data) - (q - data);
|
1998-02-27 07:54:42 +03:00
|
|
|
view->found_len = lng;
|
2000-11-20 20:25:43 +03:00
|
|
|
return 1;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2000-11-20 20:25:43 +03:00
|
|
|
return 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2005-07-12 10:04:38 +04:00
|
|
|
grow_string_buffer (char *text, gulong *size)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
char *new;
|
|
|
|
|
|
|
|
/* The grow steps */
|
|
|
|
*size += 160;
|
2000-11-20 20:25:43 +03:00
|
|
|
new = g_realloc (text, *size);
|
2005-07-12 10:04:38 +04:00
|
|
|
if (text == NULL) {
|
|
|
|
*new = '\0';
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2004-08-16 08:16:55 +04:00
|
|
|
get_line_at (WView *view, offset_type *p, offset_type *skipped)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-16 08:16:55 +04:00
|
|
|
char *buffer = NULL;
|
2005-07-12 10:04:38 +04:00
|
|
|
gulong buffer_size = 0;
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type usable_size = 0;
|
2002-10-31 01:48:59 +03:00
|
|
|
int ch;
|
2004-08-16 08:16:55 +04:00
|
|
|
const int direction = view->direction;
|
|
|
|
offset_type pos = *p;
|
|
|
|
offset_type i = 0;
|
2005-07-12 10:04:38 +04:00
|
|
|
int prev = '\0';
|
2001-04-24 18:39:38 +04:00
|
|
|
|
2005-05-23 06:03:29 +04:00
|
|
|
*skipped = 0;
|
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
if (pos == 0 && direction == -1)
|
2003-03-19 16:39:48 +03:00
|
|
|
return 0;
|
|
|
|
|
2001-04-24 18:39:38 +04:00
|
|
|
/* skip over all the possible zeros in the file */
|
|
|
|
while ((ch = get_byte (view, pos)) == 0) {
|
2005-07-12 10:04:38 +04:00
|
|
|
if (pos == 0 && direction == -1)
|
2003-03-19 16:39:48 +03:00
|
|
|
return 0;
|
2002-10-31 01:48:59 +03:00
|
|
|
pos += direction;
|
|
|
|
i++;
|
2001-04-24 18:39:38 +04:00
|
|
|
}
|
|
|
|
*skipped = i;
|
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
if (i == 0 && (pos != 0 || direction == -1)) {
|
2003-03-24 21:52:02 +03:00
|
|
|
prev = get_byte (view, pos - direction);
|
2001-04-24 18:39:38 +04:00
|
|
|
if ((prev == -1) || (prev == '\n'))
|
2005-07-12 10:04:38 +04:00
|
|
|
prev = '\0';
|
2001-04-24 18:39:38 +04:00
|
|
|
}
|
|
|
|
|
2003-03-24 21:52:02 +03:00
|
|
|
for (i = 1; ch != -1; ch = get_byte (view, pos)) {
|
|
|
|
if (i >= usable_size) {
|
1998-02-27 07:54:42 +03:00
|
|
|
buffer = grow_string_buffer (buffer, &buffer_size);
|
2003-03-24 21:52:02 +03:00
|
|
|
usable_size = buffer_size - 2; /* prev & null terminator */
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2000-11-20 20:25:43 +03:00
|
|
|
|
2003-03-24 21:52:02 +03:00
|
|
|
buffer[i++] = ch;
|
2000-11-20 20:25:43 +03:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
if (pos == 0 && direction == -1)
|
2003-03-19 16:39:48 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
pos += direction;
|
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
if (ch == '\n' || ch == '\0') {
|
2003-03-24 21:52:02 +03:00
|
|
|
i--; /* Strip newline/zero */
|
1998-02-27 07:54:42 +03:00
|
|
|
break;
|
2003-03-24 21:52:02 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2003-03-19 16:39:48 +03:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (buffer) {
|
|
|
|
buffer[0] = prev;
|
2005-07-12 10:04:38 +04:00
|
|
|
buffer[i] = '\0';
|
2003-03-21 19:01:50 +03:00
|
|
|
|
|
|
|
/* If we are searching backwards, reverse the string */
|
2005-07-12 10:04:38 +04:00
|
|
|
if (direction == -1) {
|
2003-03-21 19:01:50 +03:00
|
|
|
g_strreverse (buffer + 1);
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
*p = pos;
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
search_update_steps (WView *view)
|
|
|
|
{
|
2005-04-14 01:09:00 +04:00
|
|
|
offset_type filesize = view_get_filesize (view);
|
|
|
|
if (filesize != 0)
|
2005-02-01 01:01:53 +03:00
|
|
|
view->update_steps = 40000;
|
2004-08-16 08:16:55 +04:00
|
|
|
else /* viewing a data stream, not a file */
|
2005-04-14 01:09:00 +04:00
|
|
|
view->update_steps = filesize / 100;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Do not update the percent display but every 20 ks */
|
2005-02-01 01:01:53 +03:00
|
|
|
if (view->update_steps < 20000)
|
|
|
|
view->update_steps = 20000;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-10-31 01:48:59 +03:00
|
|
|
search (WView *view, char *text,
|
|
|
|
int (*search) (WView *, char *, char *, int))
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-08-16 08:16:55 +04:00
|
|
|
char *s = NULL; /* The line we read from the view buffer */
|
|
|
|
offset_type p, beginning, search_start;
|
|
|
|
int found_len;
|
1998-02-27 07:54:42 +03:00
|
|
|
int search_status;
|
2001-06-02 05:01:30 +04:00
|
|
|
Dlg_head *d = 0;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-07-12 10:04:38 +04:00
|
|
|
/* Used to keep track of where the line starts, when looking forward
|
|
|
|
* is the index before transfering the line; the reverse case uses
|
|
|
|
* the position returned after the line has been read */
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type forward_line_start;
|
|
|
|
offset_type reverse_line_start;
|
2005-05-23 06:03:29 +04:00
|
|
|
offset_type t;
|
1999-02-10 04:16:42 +03:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (verbose) {
|
2003-10-26 01:12:05 +04:00
|
|
|
d = create_message (D_NORMAL, _("Search"), _("Searching %s"), text);
|
1998-02-27 07:54:42 +03:00
|
|
|
mc_refresh ();
|
|
|
|
}
|
2000-11-20 20:25:43 +03:00
|
|
|
|
|
|
|
found_len = view->found_len;
|
|
|
|
search_start = view->search_start;
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->direction == 1) {
|
2005-04-17 13:50:38 +04:00
|
|
|
p = search_start + ((found_len) ? 1 : 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
} else {
|
2005-04-17 13:50:38 +04:00
|
|
|
p = search_start - ((found_len && search_start >= 1) ? 1 : 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
beginning = p;
|
|
|
|
|
|
|
|
/* Compute the percent steps */
|
|
|
|
search_update_steps (view);
|
2005-02-01 01:01:53 +03:00
|
|
|
view->update_activate = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-08-15 13:55:19 +04:00
|
|
|
enable_interrupt_key ();
|
2002-10-31 01:48:59 +03:00
|
|
|
for (;; g_free (s)) {
|
2005-02-01 01:01:53 +03:00
|
|
|
if (p >= view->update_activate) {
|
|
|
|
view->update_activate += view->update_steps;
|
2002-10-31 01:48:59 +03:00
|
|
|
if (verbose) {
|
2005-04-16 17:45:16 +04:00
|
|
|
view_percent (view, p);
|
1998-02-27 07:54:42 +03:00
|
|
|
mc_refresh ();
|
|
|
|
}
|
|
|
|
if (got_interrupt ())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
forward_line_start = p;
|
2000-11-20 20:25:43 +03:00
|
|
|
s = get_line_at (view, &p, &t);
|
1998-02-27 07:54:42 +03:00
|
|
|
reverse_line_start = p;
|
2000-11-20 20:25:43 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
if (!s)
|
|
|
|
break;
|
2000-11-20 20:25:43 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
search_status = (*search) (view, text, s + 1, match_normal);
|
2002-10-31 01:48:59 +03:00
|
|
|
if (search_status < 0) {
|
2000-11-20 20:25:43 +03:00
|
|
|
g_free (s);
|
1998-02-27 07:54:42 +03:00
|
|
|
break;
|
2000-11-20 20:25:43 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
if (search_status == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We found the string */
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2003-03-24 21:52:02 +03:00
|
|
|
/* Handle ^ and $ when regexp search starts at the middle of the line */
|
|
|
|
if (*s && !view->search_start && (search == regexp_view_search)) {
|
|
|
|
if ((*text == '^' && view->direction == 1)
|
|
|
|
|| (view->direction == -1 && text[strlen (text) - 1] == '$')
|
|
|
|
) {
|
|
|
|
continue;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
/* Record the position used to continue the search */
|
|
|
|
if (view->direction == 1)
|
2000-11-20 20:25:43 +03:00
|
|
|
t += forward_line_start;
|
1998-02-27 07:54:42 +03:00
|
|
|
else
|
2003-03-24 21:52:02 +03:00
|
|
|
t = reverse_line_start ? reverse_line_start + 3 : 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
view->search_start += t;
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (t != beginning) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view->dpy_topleft = t;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2000-11-20 20:25:43 +03:00
|
|
|
|
Glibing..... (2)
Wed Jan 27 03:17:44 1999 Timur Bakeyev <mc@bat.ru>
* Converted memory managment to Glib. Now we use g_new()/g_malloc()/
g_strdup()/g_free() routings. Also, copy_strings() replaced by
g_strconcat(), strcasecmp() -> g_strcasecmp(),and sprintf() by
g_snprintf().
* Some sequences of malloc()/sprintf() changed to g_strdup_printf().
* mad.[ch]: Modified, to work with new GLib's memory managment. Fixed
a missing #undef for tempnam, which caused dead loop. Add several new
functions to emulate GLib memory managment.
*main.c, mad.[ch]: Add a new switch "-M", which allows to redirect MAD
messages to the file.
* util.[ch], utilunix.c: Modified, deleted our variants of strcasecmp()
and strdup() - we have g_ equivalences. Remove get_full_name() - it is
similar to concat_dir_and_file(). Some other tricks with g_* functions.
* global.h: Modified, extended. Now it is main memory mangment include -
i.e. all inclusions of <stdlib.h>, <malloc.h>, <glib.h>, "fs.h", "mem.h",
"util.h" and "mad.h" done there. This elimanates problem with proper or-
der of #include's.
* All around the source - changed order of #include's, most of them gone
to global.h (see above), minor changes, like "0" -> NULL in string func-
tions.
1999-01-27 04:08:30 +03:00
|
|
|
g_free (s);
|
1998-02-27 07:54:42 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
disable_interrupt_key ();
|
2001-09-16 05:22:12 +04:00
|
|
|
if (verbose) {
|
1998-02-27 07:54:42 +03:00
|
|
|
dlg_run_done (d);
|
|
|
|
destroy_dlg (d);
|
|
|
|
}
|
2001-09-16 05:22:12 +04:00
|
|
|
if (!s) {
|
2002-10-21 08:13:49 +04:00
|
|
|
message (0, _("Search"), _(" Search string not found "));
|
1998-02-27 07:54:42 +03:00
|
|
|
view->found_len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-16 19:52:48 +04:00
|
|
|
/* Search buffer (its size is len) in the complete buffer
|
|
|
|
* returns the position where the block was found or INVALID_OFFSET
|
|
|
|
* if not found */
|
2004-08-16 08:16:55 +04:00
|
|
|
static offset_type
|
|
|
|
block_search (WView *view, const char *buffer, int len)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2003-03-19 16:39:48 +03:00
|
|
|
int direction = view->direction;
|
2004-08-16 08:16:55 +04:00
|
|
|
const char *d = buffer;
|
|
|
|
char b;
|
|
|
|
offset_type e;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
enable_interrupt_key ();
|
2003-03-19 16:39:48 +03:00
|
|
|
if (direction == 1)
|
2005-04-17 13:50:38 +04:00
|
|
|
e = view->search_start + ((view->found_len) ? 1 : 0);
|
2003-03-19 16:39:48 +03:00
|
|
|
else
|
2005-04-17 13:50:38 +04:00
|
|
|
e = view->search_start
|
|
|
|
- ((view->found_len && view->search_start >= 1) ? 1 : 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
search_update_steps (view);
|
2005-02-01 01:01:53 +03:00
|
|
|
view->update_activate = 0;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2003-03-19 16:39:48 +03:00
|
|
|
if (direction == -1) {
|
|
|
|
for (d += len - 1;; e--) {
|
2005-02-01 01:01:53 +03:00
|
|
|
if (e <= view->update_activate) {
|
|
|
|
view->update_activate -= view->update_steps;
|
2003-03-19 16:39:48 +03:00
|
|
|
if (verbose) {
|
2005-04-16 17:45:16 +04:00
|
|
|
view_percent (view, e);
|
2003-03-19 16:39:48 +03:00
|
|
|
mc_refresh ();
|
|
|
|
}
|
|
|
|
if (got_interrupt ())
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2003-03-19 16:39:48 +03:00
|
|
|
b = get_byte (view, e);
|
|
|
|
|
|
|
|
if (*d == b) {
|
|
|
|
if (d == buffer) {
|
|
|
|
disable_interrupt_key ();
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
d--;
|
|
|
|
} else {
|
|
|
|
e += buffer + len - 1 - d;
|
|
|
|
d = buffer + len - 1;
|
|
|
|
}
|
|
|
|
if (e == 0)
|
1998-02-27 07:54:42 +03:00
|
|
|
break;
|
|
|
|
}
|
2003-03-21 19:01:50 +03:00
|
|
|
} else {
|
2005-04-14 01:09:00 +04:00
|
|
|
while (get_byte (view, e) != -1) {
|
2005-02-01 01:01:53 +03:00
|
|
|
if (e >= view->update_activate) {
|
|
|
|
view->update_activate += view->update_steps;
|
2003-03-19 16:39:48 +03:00
|
|
|
if (verbose) {
|
2005-04-16 17:45:16 +04:00
|
|
|
view_percent (view, e);
|
2003-03-19 16:39:48 +03:00
|
|
|
mc_refresh ();
|
|
|
|
}
|
|
|
|
if (got_interrupt ())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
b = get_byte (view, e++);
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2003-03-19 16:39:48 +03:00
|
|
|
if (*d == b) {
|
|
|
|
d++;
|
|
|
|
if (d - buffer == len) {
|
|
|
|
disable_interrupt_key ();
|
|
|
|
return e - len;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
e -= d - buffer;
|
|
|
|
d = buffer;
|
2001-08-06 19:33:38 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2003-03-21 19:01:50 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
disable_interrupt_key ();
|
2004-10-16 19:52:48 +04:00
|
|
|
return INVALID_OFFSET;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2001-07-10 03:19:23 +04:00
|
|
|
/*
|
|
|
|
* Search in the hex mode. Supported input:
|
|
|
|
* - numbers (oct, dec, hex). Each of them matches one byte.
|
|
|
|
* - strings in double quotes. Matches exactly without quotes.
|
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
static void
|
2004-08-16 08:16:55 +04:00
|
|
|
hex_search (WView *view, const char *text)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2001-09-03 00:34:44 +04:00
|
|
|
char *buffer; /* Parsed search string */
|
|
|
|
char *cur; /* Current position in it */
|
2002-10-31 01:48:59 +03:00
|
|
|
int block_len; /* Length of the search string */
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type pos; /* Position of the string in the file */
|
2002-10-31 01:48:59 +03:00
|
|
|
int parse_error = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2001-07-10 21:42:25 +04:00
|
|
|
if (!*text) {
|
|
|
|
view->found_len = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-07-10 03:19:23 +04:00
|
|
|
/* buffer will never be longer that text */
|
|
|
|
buffer = g_new (char, strlen (text));
|
2001-09-03 00:34:44 +04:00
|
|
|
cur = buffer;
|
2001-07-10 03:19:23 +04:00
|
|
|
|
|
|
|
/* First convert the string to a stream of bytes */
|
2001-07-10 21:42:25 +04:00
|
|
|
while (*text) {
|
2001-07-10 03:19:23 +04:00
|
|
|
int val;
|
|
|
|
int ptr;
|
|
|
|
|
2001-09-03 00:34:44 +04:00
|
|
|
/* Skip leading spaces */
|
|
|
|
if (*text == ' ' || *text == '\t') {
|
|
|
|
text++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-07-10 03:19:23 +04:00
|
|
|
/* %i matches octal, decimal, and hexadecimal numbers */
|
2001-07-10 21:42:25 +04:00
|
|
|
if (sscanf (text, "%i%n", &val, &ptr) > 0) {
|
2001-07-10 03:19:23 +04:00
|
|
|
/* Allow signed and unsigned char in the user input */
|
|
|
|
if (val < -128 || val > 255) {
|
|
|
|
parse_error = 1;
|
1998-02-27 07:54:42 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-09-03 00:34:44 +04:00
|
|
|
*cur++ = (char) val;
|
2001-07-10 21:42:25 +04:00
|
|
|
text += ptr;
|
2001-07-10 03:19:23 +04:00
|
|
|
continue;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2001-07-10 03:19:23 +04:00
|
|
|
/* Try quoted string, strip quotes */
|
2001-09-03 00:34:44 +04:00
|
|
|
if (*text == '"') {
|
2004-09-25 05:12:09 +04:00
|
|
|
const char *next_quote;
|
2001-09-03 00:34:44 +04:00
|
|
|
|
|
|
|
text++;
|
|
|
|
next_quote = strchr (text, '"');
|
|
|
|
if (next_quote) {
|
|
|
|
memcpy (cur, text, next_quote - text);
|
|
|
|
cur += next_quote - text;
|
|
|
|
text = next_quote + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* fall through */
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2001-07-10 03:19:23 +04:00
|
|
|
|
|
|
|
parse_error = 1;
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2001-07-10 03:19:23 +04:00
|
|
|
|
2001-09-03 00:34:44 +04:00
|
|
|
block_len = cur - buffer;
|
|
|
|
|
2001-07-10 03:19:23 +04:00
|
|
|
/* No valid bytes in the user input */
|
|
|
|
if (block_len <= 0 || parse_error) {
|
2002-10-21 08:13:49 +04:00
|
|
|
message (0, _("Search"), _("Invalid hex search expression"));
|
2001-07-10 03:19:23 +04:00
|
|
|
g_free (buffer);
|
|
|
|
view->found_len = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Then start the search */
|
|
|
|
pos = block_search (view, buffer, block_len);
|
2001-07-10 03:19:23 +04:00
|
|
|
|
2001-07-10 21:42:25 +04:00
|
|
|
g_free (buffer);
|
|
|
|
|
2004-10-16 19:52:48 +04:00
|
|
|
if (pos == INVALID_OFFSET) {
|
2002-10-21 08:13:49 +04:00
|
|
|
message (0, _("Search"), _(" Search string not found "));
|
1998-02-27 07:54:42 +03:00
|
|
|
view->found_len = 0;
|
|
|
|
return;
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2001-08-06 19:33:38 +04:00
|
|
|
view->search_start = pos;
|
1998-02-27 07:54:42 +03:00
|
|
|
view->found_len = block_len;
|
|
|
|
/* Set the edit cursor to the search position, left nibble */
|
2005-05-21 14:23:57 +04:00
|
|
|
view->hex_cursor = view->search_start;
|
2005-04-20 00:33:51 +04:00
|
|
|
view->hexedit_lownibble = FALSE;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Adjust the file offset */
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_topleft = pos - pos % view->bytes_per_line;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
static int
|
|
|
|
regexp_view_search (WView *view, char *pattern, char *string,
|
|
|
|
int match_type)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
static regex_t r;
|
|
|
|
static char *old_pattern = NULL;
|
|
|
|
static int old_type;
|
|
|
|
regmatch_t pmatch[1];
|
|
|
|
int i, flags = REG_ICASE;
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (!old_pattern || strcmp (old_pattern, pattern)
|
|
|
|
|| old_type != match_type) {
|
|
|
|
if (old_pattern) {
|
1998-02-27 07:54:42 +03:00
|
|
|
regfree (&r);
|
Glibing..... (2)
Wed Jan 27 03:17:44 1999 Timur Bakeyev <mc@bat.ru>
* Converted memory managment to Glib. Now we use g_new()/g_malloc()/
g_strdup()/g_free() routings. Also, copy_strings() replaced by
g_strconcat(), strcasecmp() -> g_strcasecmp(),and sprintf() by
g_snprintf().
* Some sequences of malloc()/sprintf() changed to g_strdup_printf().
* mad.[ch]: Modified, to work with new GLib's memory managment. Fixed
a missing #undef for tempnam, which caused dead loop. Add several new
functions to emulate GLib memory managment.
*main.c, mad.[ch]: Add a new switch "-M", which allows to redirect MAD
messages to the file.
* util.[ch], utilunix.c: Modified, deleted our variants of strcasecmp()
and strdup() - we have g_ equivalences. Remove get_full_name() - it is
similar to concat_dir_and_file(). Some other tricks with g_* functions.
* global.h: Modified, extended. Now it is main memory mangment include -
i.e. all inclusions of <stdlib.h>, <malloc.h>, <glib.h>, "fs.h", "mem.h",
"util.h" and "mad.h" done there. This elimanates problem with proper or-
der of #include's.
* All around the source - changed order of #include's, most of them gone
to global.h (see above), minor changes, like "0" -> NULL in string func-
tions.
1999-01-27 04:08:30 +03:00
|
|
|
g_free (old_pattern);
|
1998-02-27 07:54:42 +03:00
|
|
|
old_pattern = 0;
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
for (i = 0; pattern[i] != 0; i++) {
|
2005-05-11 05:16:58 +04:00
|
|
|
if (isupper ((unsigned char) pattern[i])) {
|
1998-02-27 07:54:42 +03:00
|
|
|
flags = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
flags |= REG_EXTENDED;
|
2002-10-31 01:48:59 +03:00
|
|
|
if (regcomp (&r, pattern, flags)) {
|
1998-03-25 08:16:00 +03:00
|
|
|
message (1, MSG_ERROR, _(" Invalid regular expression "));
|
1998-02-27 07:54:42 +03:00
|
|
|
return -1;
|
|
|
|
}
|
Glibing..... (2)
Wed Jan 27 03:17:44 1999 Timur Bakeyev <mc@bat.ru>
* Converted memory managment to Glib. Now we use g_new()/g_malloc()/
g_strdup()/g_free() routings. Also, copy_strings() replaced by
g_strconcat(), strcasecmp() -> g_strcasecmp(),and sprintf() by
g_snprintf().
* Some sequences of malloc()/sprintf() changed to g_strdup_printf().
* mad.[ch]: Modified, to work with new GLib's memory managment. Fixed
a missing #undef for tempnam, which caused dead loop. Add several new
functions to emulate GLib memory managment.
*main.c, mad.[ch]: Add a new switch "-M", which allows to redirect MAD
messages to the file.
* util.[ch], utilunix.c: Modified, deleted our variants of strcasecmp()
and strdup() - we have g_ equivalences. Remove get_full_name() - it is
similar to concat_dir_and_file(). Some other tricks with g_* functions.
* global.h: Modified, extended. Now it is main memory mangment include -
i.e. all inclusions of <stdlib.h>, <malloc.h>, <glib.h>, "fs.h", "mem.h",
"util.h" and "mad.h" done there. This elimanates problem with proper or-
der of #include's.
* All around the source - changed order of #include's, most of them gone
to global.h (see above), minor changes, like "0" -> NULL in string func-
tions.
1999-01-27 04:08:30 +03:00
|
|
|
old_pattern = g_strdup (pattern);
|
1998-02-27 07:54:42 +03:00
|
|
|
old_type = match_type;
|
|
|
|
}
|
|
|
|
if (regexec (&r, string, 1, pmatch, 0) != 0)
|
|
|
|
return 0;
|
|
|
|
view->found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
|
|
|
|
view->search_start = pmatch[0].rm_so;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
static void
|
2005-06-28 16:28:35 +04:00
|
|
|
do_regexp_search (WView *view, char *regexp)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
view->search_exp = regexp;
|
|
|
|
search (view, regexp, regexp_view_search);
|
|
|
|
/* Had a refresh here */
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
static void
|
2005-06-28 16:28:35 +04:00
|
|
|
do_normal_search (WView *view, char *text)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
view->search_exp = text;
|
|
|
|
if (view->hex_mode)
|
|
|
|
hex_search (view, text);
|
2002-10-31 01:48:59 +03:00
|
|
|
else
|
1998-02-27 07:54:42 +03:00
|
|
|
search (view, text, icase_search_p);
|
|
|
|
/* Had a refresh here */
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Real view only */
|
2002-10-31 01:48:59 +03:00
|
|
|
static void
|
|
|
|
view_help_cmd (void)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2001-06-09 11:13:46 +04:00
|
|
|
interactive_display (NULL, "[Internal File Viewer]");
|
1998-02-27 07:54:42 +03:00
|
|
|
/*
|
2002-10-31 01:48:59 +03:00
|
|
|
view_refresh (0);
|
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2005-05-21 14:04:03 +04:00
|
|
|
/* Toggle between hexview and hexedit mode */
|
2002-10-31 01:48:59 +03:00
|
|
|
static void
|
2003-10-23 23:53:22 +04:00
|
|
|
toggle_hexedit_mode (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-05-21 14:02:09 +04:00
|
|
|
view->hexedit_mode = !view->hexedit_mode;
|
2003-10-23 23:53:22 +04:00
|
|
|
view_labels (view);
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
2003-10-23 23:53:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Toggle between wrapped and unwrapped view */
|
|
|
|
static void
|
|
|
|
toggle_wrap_mode (WView *view)
|
|
|
|
{
|
2005-04-27 22:39:21 +04:00
|
|
|
view->text_wrap_mode = !view->text_wrap_mode;
|
2005-05-26 13:08:54 +04:00
|
|
|
if (view->text_wrap_mode) {
|
|
|
|
view_fix_cursor_position (view);
|
|
|
|
} else {
|
|
|
|
offset_type line;
|
|
|
|
|
|
|
|
view_offset_to_coord (view, &line, &(view->dpy_text_column), view->dpy_topleft);
|
|
|
|
view_coord_to_offset (view, &(view->dpy_topleft), line, 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
view_labels (view);
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2003-10-23 23:53:22 +04:00
|
|
|
/* Toggle between hex view and text view */
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
toggle_hex_mode (WView *view)
|
|
|
|
{
|
2005-04-14 15:02:21 +04:00
|
|
|
view->hex_mode = !view->hex_mode;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->hex_mode) {
|
2005-08-15 14:22:18 +04:00
|
|
|
view->hex_cursor = view->dpy_topleft;
|
|
|
|
view->dpy_topleft =
|
2005-05-26 13:08:54 +04:00
|
|
|
offset_rounddown (view->dpy_topleft, view->bytes_per_line);
|
1998-02-27 07:54:42 +03:00
|
|
|
view->widget.options |= W_WANT_CURSOR;
|
|
|
|
} else {
|
2005-05-26 13:08:54 +04:00
|
|
|
view->dpy_topleft = view->hex_cursor;
|
|
|
|
view_moveto_bol (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
view->widget.options &= ~W_WANT_CURSOR;
|
|
|
|
}
|
|
|
|
altered_hex_mode = 1;
|
|
|
|
view_labels (view);
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2003-10-24 01:23:33 +04:00
|
|
|
/* Text view */
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
goto_line (WView *view)
|
|
|
|
{
|
2005-05-26 13:08:54 +04:00
|
|
|
char *answer, *answer_end, prompt[BUF_SMALL];
|
|
|
|
offset_type line, col;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
view_offset_to_coord (view, &line, &col, view->dpy_topleft);
|
2005-04-14 01:09:00 +04:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
g_snprintf (prompt, sizeof (prompt),
|
|
|
|
_(" The current line number is %d.\n"
|
2005-05-26 13:08:54 +04:00
|
|
|
" Enter the new line number:"), (int) (line + 1));
|
|
|
|
answer = input_dialog (_(" Goto line "), prompt, "");
|
|
|
|
if (answer && answer[0] != '\0') {
|
|
|
|
errno = 0;
|
|
|
|
line = strtoul (answer, &answer_end, 10);
|
|
|
|
if (*answer_end == '\0' && errno == 0 && line >= 1)
|
|
|
|
view_moveto (view, line - 1, 0);
|
|
|
|
}
|
|
|
|
g_free (answer);
|
1998-02-27 07:54:42 +03:00
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
1999-06-25 01:53:40 +04:00
|
|
|
/* Hex view */
|
2001-06-15 02:33:00 +04:00
|
|
|
static void
|
1999-06-25 01:53:40 +04:00
|
|
|
goto_addr (WView *view)
|
|
|
|
{
|
2002-10-31 01:48:59 +03:00
|
|
|
char *line, *error, prompt[BUF_SMALL];
|
2004-08-16 08:16:55 +04:00
|
|
|
offset_type addr;
|
1999-06-25 01:53:40 +04:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
g_snprintf (prompt, sizeof (prompt),
|
|
|
|
_(" The current address is 0x%lx.\n"
|
2005-05-21 14:23:57 +04:00
|
|
|
" Enter the new address:"), view->hex_cursor);
|
1999-06-25 01:53:40 +04:00
|
|
|
line = input_dialog (_(" Goto Address "), prompt, "");
|
2002-10-31 01:48:59 +03:00
|
|
|
if (line) {
|
1999-06-25 01:53:40 +04:00
|
|
|
if (*line) {
|
2004-08-16 08:16:55 +04:00
|
|
|
addr = strtoul (line, &error, 0);
|
2005-04-14 01:09:00 +04:00
|
|
|
if ((*error == '\0') && get_byte (view, addr) != -1) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_moveto_offset (view, addr);
|
2002-10-31 01:48:59 +03:00
|
|
|
}
|
|
|
|
}
|
1999-06-25 01:53:40 +04:00
|
|
|
g_free (line);
|
|
|
|
}
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1999-06-25 01:53:40 +04:00
|
|
|
}
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Both views */
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
regexp_search (WView *view, int direction)
|
|
|
|
{
|
2005-04-26 19:06:38 +04:00
|
|
|
char *regexp = str_unconst ("");
|
1998-02-27 07:54:42 +03:00
|
|
|
static char *old = 0;
|
|
|
|
|
|
|
|
/* This is really an F6 key handler */
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->hex_mode) {
|
|
|
|
/* Save it without a confirmation prompt */
|
2002-05-30 17:12:56 +04:00
|
|
|
if (view->change_list)
|
2005-04-19 00:12:18 +04:00
|
|
|
view_hexedit_save_changes (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
return;
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-04-17 13:50:38 +04:00
|
|
|
if (old)
|
|
|
|
regexp = old;
|
2002-10-21 08:13:49 +04:00
|
|
|
regexp = input_dialog (_("Search"), _(" Enter regexp:"), regexp);
|
2002-10-31 01:48:59 +03:00
|
|
|
if ((!regexp)) {
|
2000-11-20 20:25:43 +03:00
|
|
|
return;
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
if ((!*regexp)) {
|
2000-11-20 20:25:43 +03:00
|
|
|
g_free (regexp);
|
1998-02-27 07:54:42 +03:00
|
|
|
return;
|
|
|
|
}
|
2004-09-25 02:22:35 +04:00
|
|
|
g_free (old);
|
1998-02-27 07:54:42 +03:00
|
|
|
old = regexp;
|
|
|
|
view->direction = direction;
|
|
|
|
do_regexp_search (view, regexp);
|
|
|
|
|
|
|
|
view->last_search = do_regexp_search;
|
|
|
|
}
|
|
|
|
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
regexp_search_cmd (WView *view)
|
|
|
|
{
|
|
|
|
regexp_search (view, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Both views */
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
2005-06-28 16:25:34 +04:00
|
|
|
normal_search_cmd (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
static char *old;
|
2005-04-26 19:06:38 +04:00
|
|
|
char *exp = old ? old : str_unconst ("");
|
2003-03-19 16:39:48 +03:00
|
|
|
|
|
|
|
enum {
|
|
|
|
SEARCH_DLG_HEIGHT = 8,
|
|
|
|
SEARCH_DLG_WIDTH = 58
|
|
|
|
};
|
|
|
|
|
|
|
|
static int replace_backwards;
|
|
|
|
int treplace_backwards = replace_backwards;
|
|
|
|
|
|
|
|
static QuickWidget quick_widgets[] = {
|
|
|
|
{quick_button, 6, 10, 5, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0,
|
|
|
|
B_CANCEL,
|
|
|
|
0, 0, NULL},
|
|
|
|
{quick_button, 2, 10, 5, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER,
|
|
|
|
0, 0, NULL},
|
|
|
|
{quick_checkbox, 3, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT,
|
|
|
|
N_("&Backwards"), 0, 0,
|
|
|
|
0, 0, NULL},
|
|
|
|
{quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0,
|
|
|
|
0, 0, N_("Search")},
|
|
|
|
{quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT,
|
|
|
|
N_(" Enter search string:"), 0, 0,
|
|
|
|
0, 0, 0},
|
2004-08-15 22:24:06 +04:00
|
|
|
NULL_QuickWidget
|
2003-03-19 16:39:48 +03:00
|
|
|
};
|
|
|
|
static QuickDialog Quick_input = {
|
|
|
|
SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
|
|
|
|
"[Input Line Keys]", quick_widgets, 0
|
|
|
|
};
|
2002-10-31 14:55:35 +03:00
|
|
|
convert_to_display (old);
|
2001-06-06 02:49:15 +04:00
|
|
|
|
2003-03-19 16:39:48 +03:00
|
|
|
quick_widgets[2].result = &treplace_backwards;
|
|
|
|
quick_widgets[3].str_result = &exp;
|
|
|
|
quick_widgets[3].text = exp;
|
2002-10-31 02:42:21 +03:00
|
|
|
|
2003-03-19 16:39:48 +03:00
|
|
|
if (quick_dialog (&Quick_input) == B_CANCEL) {
|
2002-10-31 02:42:21 +03:00
|
|
|
convert_from_input (old);
|
1998-02-27 07:54:42 +03:00
|
|
|
return;
|
|
|
|
}
|
2003-03-19 16:39:48 +03:00
|
|
|
replace_backwards = treplace_backwards;
|
|
|
|
|
|
|
|
convert_from_input (old);
|
|
|
|
|
|
|
|
if ((!exp)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((!*exp)) {
|
|
|
|
g_free (exp);
|
|
|
|
return;
|
|
|
|
}
|
2002-10-29 16:01:09 +03:00
|
|
|
|
2004-09-25 02:22:35 +04:00
|
|
|
g_free (old);
|
1998-02-27 07:54:42 +03:00
|
|
|
old = exp;
|
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
convert_from_input (exp);
|
2001-06-06 02:49:15 +04:00
|
|
|
|
2003-03-19 16:39:48 +03:00
|
|
|
view->direction = replace_backwards ? -1 : 1;
|
1998-02-27 07:54:42 +03:00
|
|
|
do_normal_search (view, exp);
|
|
|
|
view->last_search = do_normal_search;
|
|
|
|
}
|
|
|
|
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
change_viewer (WView *view)
|
|
|
|
{
|
I improved the movement keys of the internal viewer a little bit.
Now in wrap mode the End key and cursor up key behave much better
(e.g. when viewing binary files with lots of wrapped lines).
It's not perfekt but it's better than it used to be.
Tue Apr 28 06:52:24 1998 Norbert Warmuth <k3190@fh-sw.de>
* gnome/gcmd.c (gnome_open_terminal): Changed my_system(1,...) to
my_system(EXECUTE_AS_SHELL,...)
Tue Apr 28 06:06:03 1998 Norbert Warmuth <k3190@fh-sw.de>
* vfs/extfs.c (extfs_open, extfs_close): Changed my_system(1,...)
to my_system(EXECUTE_AS_SHELL,...), this fixes the broken copyin and
copyout in 4.1.32.
Tue Apr 28 06:11:08 1998 Norbert Warmuth <k3190@fh-sw.de>
* view.c (toggle_wrap_mode, toggle_hex_mode): Force recalculation
of bottom_first (we mustn't use an already calculated and cached
value because it is invalid for the new mode and the End key would
not move to the end of the file).
* configure.in: Renamed the option `--with-our-slang' to
`--with-included-slang' (this one looks better because we also
have an `--with-included-gettext').
Make the option `--with-ext2undel' recognice a given path.
* cmd.c (view_file_at_line): In plain view (F13) set the default
magic flag to zero in order to view the file content unprocessed
(esp. don't uncompress files if they are compressed). The
view_simple_cmd got broken when the default magic flag in view.c
was changed from 0 to 1.
* view.c (do_view_init, goto_line): Set wrap mode temporary off
to make goto line number work, i.e. `line number' now always means
line number in file and not line number on screen (in wrap mode
one long line wrapped once is displayed in two lines on the screen).
That's important when the viewer is invoked from the find file
dialog to display even in wrap mode approxiamtly the part of the
file where we found the content we searched for.
(move_forward2): In wrap mode lines were sometimes counted wrong
causing cursor up to move more than one line.
(move_backward2): Fixed the movement in wrap mode.
(change_viewer): Always re-init viewer when we have a filename,
i. e. if the viewer is invoked with simple_view_cmd then we can switch
with the F8 key between unprocessed file content und uncompressed
file content.
(view_init): re-init view also when magic flag was altered
1998-04-28 18:19:48 +04:00
|
|
|
char *s;
|
|
|
|
char *t;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
|
I improved the movement keys of the internal viewer a little bit.
Now in wrap mode the End key and cursor up key behave much better
(e.g. when viewing binary files with lots of wrapped lines).
It's not perfekt but it's better than it used to be.
Tue Apr 28 06:52:24 1998 Norbert Warmuth <k3190@fh-sw.de>
* gnome/gcmd.c (gnome_open_terminal): Changed my_system(1,...) to
my_system(EXECUTE_AS_SHELL,...)
Tue Apr 28 06:06:03 1998 Norbert Warmuth <k3190@fh-sw.de>
* vfs/extfs.c (extfs_open, extfs_close): Changed my_system(1,...)
to my_system(EXECUTE_AS_SHELL,...), this fixes the broken copyin and
copyout in 4.1.32.
Tue Apr 28 06:11:08 1998 Norbert Warmuth <k3190@fh-sw.de>
* view.c (toggle_wrap_mode, toggle_hex_mode): Force recalculation
of bottom_first (we mustn't use an already calculated and cached
value because it is invalid for the new mode and the End key would
not move to the end of the file).
* configure.in: Renamed the option `--with-our-slang' to
`--with-included-slang' (this one looks better because we also
have an `--with-included-gettext').
Make the option `--with-ext2undel' recognice a given path.
* cmd.c (view_file_at_line): In plain view (F13) set the default
magic flag to zero in order to view the file content unprocessed
(esp. don't uncompress files if they are compressed). The
view_simple_cmd got broken when the default magic flag in view.c
was changed from 0 to 1.
* view.c (do_view_init, goto_line): Set wrap mode temporary off
to make goto line number work, i.e. `line number' now always means
line number in file and not line number on screen (in wrap mode
one long line wrapped once is displayed in two lines on the screen).
That's important when the viewer is invoked from the find file
dialog to display even in wrap mode approxiamtly the part of the
file where we found the content we searched for.
(move_forward2): In wrap mode lines were sometimes counted wrong
causing cursor up to move more than one line.
(move_backward2): Fixed the movement in wrap mode.
(change_viewer): Always re-init viewer when we have a filename,
i. e. if the viewer is invoked with simple_view_cmd then we can switch
with the F8 key between unprocessed file content und uncompressed
file content.
(view_init): re-init view also when magic flag was altered
1998-04-28 18:19:48 +04:00
|
|
|
if (*view->filename) {
|
2002-10-31 01:48:59 +03:00
|
|
|
altered_magic_flag = 1;
|
2005-04-14 15:12:01 +04:00
|
|
|
view->magic_mode = !view->magic_mode;
|
2002-10-31 01:48:59 +03:00
|
|
|
s = g_strdup (view->filename);
|
2005-04-07 15:23:53 +04:00
|
|
|
t = g_strdup (view->command);
|
I improved the movement keys of the internal viewer a little bit.
Now in wrap mode the End key and cursor up key behave much better
(e.g. when viewing binary files with lots of wrapped lines).
It's not perfekt but it's better than it used to be.
Tue Apr 28 06:52:24 1998 Norbert Warmuth <k3190@fh-sw.de>
* gnome/gcmd.c (gnome_open_terminal): Changed my_system(1,...) to
my_system(EXECUTE_AS_SHELL,...)
Tue Apr 28 06:06:03 1998 Norbert Warmuth <k3190@fh-sw.de>
* vfs/extfs.c (extfs_open, extfs_close): Changed my_system(1,...)
to my_system(EXECUTE_AS_SHELL,...), this fixes the broken copyin and
copyout in 4.1.32.
Tue Apr 28 06:11:08 1998 Norbert Warmuth <k3190@fh-sw.de>
* view.c (toggle_wrap_mode, toggle_hex_mode): Force recalculation
of bottom_first (we mustn't use an already calculated and cached
value because it is invalid for the new mode and the End key would
not move to the end of the file).
* configure.in: Renamed the option `--with-our-slang' to
`--with-included-slang' (this one looks better because we also
have an `--with-included-gettext').
Make the option `--with-ext2undel' recognice a given path.
* cmd.c (view_file_at_line): In plain view (F13) set the default
magic flag to zero in order to view the file content unprocessed
(esp. don't uncompress files if they are compressed). The
view_simple_cmd got broken when the default magic flag in view.c
was changed from 0 to 1.
* view.c (do_view_init, goto_line): Set wrap mode temporary off
to make goto line number work, i.e. `line number' now always means
line number in file and not line number on screen (in wrap mode
one long line wrapped once is displayed in two lines on the screen).
That's important when the viewer is invoked from the find file
dialog to display even in wrap mode approxiamtly the part of the
file where we found the content we searched for.
(move_forward2): In wrap mode lines were sometimes counted wrong
causing cursor up to move more than one line.
(move_backward2): Fixed the movement in wrap mode.
(change_viewer): Always re-init viewer when we have a filename,
i. e. if the viewer is invoked with simple_view_cmd then we can switch
with the F8 key between unprocessed file content und uncompressed
file content.
(view_init): re-init view also when magic flag was altered
1998-04-28 18:19:48 +04:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
view_done (view);
|
2005-04-14 12:00:14 +04:00
|
|
|
view_load (view, t, s, 0);
|
2002-10-31 01:48:59 +03:00
|
|
|
g_free (s);
|
2004-09-25 02:22:35 +04:00
|
|
|
g_free (t);
|
2002-10-31 01:48:59 +03:00
|
|
|
view_labels (view);
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
change_nroff (WView *view)
|
|
|
|
{
|
2005-04-14 15:06:12 +04:00
|
|
|
view->text_nroff_mode = !view->text_nroff_mode;
|
1998-02-27 07:54:42 +03:00
|
|
|
altered_nroff_flag = 1;
|
|
|
|
view_labels (view);
|
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Real view only */
|
|
|
|
static void
|
1998-03-13 06:44:54 +03:00
|
|
|
view_quit_cmd (WView *view)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
if (view_ok_to_quit (view))
|
1998-05-05 10:18:55 +04:00
|
|
|
dlg_stop (view->widget.parent);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2003-10-23 23:53:22 +04:00
|
|
|
/* Define labels and handlers for functional keys */
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
view_labels (WView *view)
|
|
|
|
{
|
|
|
|
Dlg_head *h = view->widget.parent;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-07-20 19:39:47 +04:00
|
|
|
buttonbar_set_label (h, 1, gettext_ui("ButtonBar|Help"), view_help_cmd);
|
|
|
|
|
|
|
|
my_define (h, 10, gettext_ui("ButtonBar|Quit"), view_quit_cmd, view);
|
|
|
|
my_define (h, 4, view->hex_mode
|
|
|
|
? gettext_ui("ButtonBar|Ascii")
|
|
|
|
: gettext_ui("ButtonBar|Hex"),
|
|
|
|
toggle_hex_mode, view);
|
|
|
|
my_define (h, 5, view->hex_mode
|
|
|
|
? gettext_ui("ButtonBar|Goto")
|
|
|
|
: gettext_ui("ButtonBar|Line"),
|
|
|
|
view->hex_mode ? goto_addr : goto_line, view);
|
|
|
|
my_define (h, 6, view->hex_mode
|
|
|
|
? gettext_ui("ButtonBar|Save")
|
|
|
|
: gettext_ui("ButtonBar|RxSrch"),
|
|
|
|
regexp_search_cmd, view);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-05-21 14:34:16 +04:00
|
|
|
if (view->hex_mode) {
|
|
|
|
if (view->hexedit_mode) {
|
2005-07-20 19:39:47 +04:00
|
|
|
my_define (h, 2, gettext_ui("ButtonBar|View"),
|
|
|
|
toggle_hexedit_mode, view);
|
2005-05-21 14:34:16 +04:00
|
|
|
} else if (view->datasource == DS_FILE) {
|
2005-07-20 19:39:47 +04:00
|
|
|
my_define (h, 2, gettext_ui("ButtonBar|Edit"),
|
|
|
|
toggle_hexedit_mode, view);
|
2005-05-21 14:34:16 +04:00
|
|
|
} else {
|
|
|
|
my_define (h, 2, "", NULL, view);
|
|
|
|
}
|
2005-07-20 19:39:47 +04:00
|
|
|
} else {
|
|
|
|
my_define (h, 2, view->text_wrap_mode
|
|
|
|
? gettext_ui("ButtonBar|UnWrap")
|
|
|
|
: gettext_ui("ButtonBar|Wrap"),
|
|
|
|
toggle_wrap_mode, view);
|
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-07-20 19:39:47 +04:00
|
|
|
my_define (h, 7, view->hex_mode
|
|
|
|
? gettext_ui("ButtonBar|HxSrch")
|
|
|
|
: gettext_ui("ButtonBar|Search"),
|
|
|
|
normal_search_cmd, view);
|
|
|
|
my_define (h, 8, view->magic_mode
|
|
|
|
? gettext_ui("ButtonBar|Raw")
|
|
|
|
: gettext_ui("ButtonBar|Parse"),
|
|
|
|
change_viewer, view);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-04-16 17:45:16 +04:00
|
|
|
/* don't override the key to access the main menu */
|
|
|
|
if (!view_is_in_panel (view)) {
|
2005-07-20 19:39:47 +04:00
|
|
|
my_define (h, 9, view->text_nroff_mode
|
|
|
|
? gettext_ui("ButtonBar|Unform")
|
|
|
|
: gettext_ui("ButtonBar|Format"),
|
|
|
|
change_nroff, view);
|
|
|
|
my_define (h, 3, gettext_ui("ButtonBar|Quit"), view_quit_cmd, view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2005-02-08 12:53:51 +03:00
|
|
|
buttonbar_redraw (h);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2003-11-21 09:27:14 +03:00
|
|
|
/* Check for left and right arrows, possibly with modifiers */
|
|
|
|
static cb_ret_t
|
1998-02-27 07:54:42 +03:00
|
|
|
check_left_right_keys (WView *view, int c)
|
|
|
|
{
|
2003-11-21 09:27:14 +03:00
|
|
|
if (c == KEY_LEFT) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_left (view, 1);
|
2003-11-21 09:27:14 +03:00
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == KEY_RIGHT) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_right (view, 1);
|
2003-11-21 09:27:14 +03:00
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2003-11-21 09:27:14 +03:00
|
|
|
/* Ctrl with arrows moves by 10 postions in the unwrap mode */
|
2005-04-14 15:14:42 +04:00
|
|
|
if (view->hex_mode || view->text_wrap_mode)
|
2003-11-21 09:27:14 +03:00
|
|
|
return MSG_NOT_HANDLED;
|
|
|
|
|
|
|
|
if (c == (KEY_M_CTRL | KEY_LEFT)) {
|
2005-05-21 14:17:35 +04:00
|
|
|
if (view->dpy_text_column >= 10)
|
|
|
|
view->dpy_text_column -= 10;
|
2005-04-16 18:25:52 +04:00
|
|
|
else
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_text_column = 0;
|
2003-11-21 09:27:14 +03:00
|
|
|
view->dirty++;
|
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == (KEY_M_CTRL | KEY_RIGHT)) {
|
2005-07-03 19:31:55 +04:00
|
|
|
if (view->dpy_text_column <= OFFSETTYPE_MAX - 10)
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_text_column += 10;
|
2005-04-16 18:25:52 +04:00
|
|
|
else
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_text_column = OFFSETTYPE_MAX;
|
2003-11-21 09:27:14 +03:00
|
|
|
view->dirty++;
|
|
|
|
return MSG_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MSG_NOT_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2002-08-27 23:10:54 +04:00
|
|
|
static void
|
1998-03-14 03:42:23 +03:00
|
|
|
continue_search (WView *view)
|
|
|
|
{
|
2002-10-31 01:48:59 +03:00
|
|
|
if (view->last_search) {
|
|
|
|
(*view->last_search) (view, view->search_exp);
|
1998-03-14 03:42:23 +03:00
|
|
|
} else {
|
|
|
|
/* if not... then ask for an expression */
|
2005-06-28 16:25:34 +04:00
|
|
|
normal_search_cmd (view);
|
1998-03-14 03:42:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
static void view_cmk_move_up (void *w, int n) {
|
|
|
|
view_move_up ((WView *) w, n);
|
|
|
|
}
|
|
|
|
static void view_cmk_move_down (void *w, int n) {
|
|
|
|
view_move_down ((WView *) w, n);
|
|
|
|
}
|
|
|
|
static void view_cmk_moveto_top (void *w, int n) {
|
|
|
|
(void) &n;
|
|
|
|
view_moveto_top ((WView *) w);
|
|
|
|
}
|
|
|
|
static void view_cmk_moveto_bottom (void *w, int n) {
|
|
|
|
(void) &n;
|
|
|
|
view_moveto_bottom ((WView *) w);
|
2005-05-26 13:07:40 +04:00
|
|
|
}
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Both views */
|
2003-09-11 02:48:54 +04:00
|
|
|
static cb_ret_t
|
1998-02-27 07:54:42 +03:00
|
|
|
view_handle_key (WView *view, int c)
|
|
|
|
{
|
2002-10-31 02:42:21 +03:00
|
|
|
c = convert_from_input_c (c);
|
2001-06-06 02:49:15 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
if (view->hex_mode) {
|
2002-10-31 01:48:59 +03:00
|
|
|
switch (c) {
|
2005-05-26 13:08:54 +04:00
|
|
|
case '\t':
|
2005-04-14 14:59:02 +04:00
|
|
|
view->hexview_in_text = !view->hexview_in_text;
|
2002-10-31 01:48:59 +03:00
|
|
|
view->dirty++;
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
case XCTRL ('a'):
|
|
|
|
view_moveto_bol (view);
|
2002-10-31 01:48:59 +03:00
|
|
|
view->dirty++;
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
case XCTRL ('b'):
|
|
|
|
view_move_left (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
case XCTRL ('e'):
|
|
|
|
view_moveto_eol (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
case XCTRL ('f'):
|
|
|
|
view_move_right (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
}
|
|
|
|
|
2003-10-24 02:20:15 +04:00
|
|
|
if (view->hexedit_mode
|
|
|
|
&& view_handle_editkey (view, c) == MSG_HANDLED)
|
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
if (check_left_right_keys (view, c))
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
if (check_movement_keys (c, view->data_area.height + 1, view,
|
2005-05-26 13:08:54 +04:00
|
|
|
view_cmk_move_up, view_cmk_move_down,
|
|
|
|
view_cmk_moveto_top, view_cmk_moveto_bottom))
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2005-05-26 13:08:54 +04:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
switch (c) {
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
case '?':
|
|
|
|
regexp_search (view, -1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case '/':
|
|
|
|
regexp_search (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Continue search */
|
2002-10-31 01:48:59 +03:00
|
|
|
case XCTRL ('s'):
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'n':
|
2002-10-31 01:48:59 +03:00
|
|
|
case KEY_F (17):
|
1998-03-14 03:42:23 +03:00
|
|
|
continue_search (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
case XCTRL ('r'):
|
|
|
|
if (view->last_search) {
|
|
|
|
(*view->last_search) (view, view->search_exp);
|
1998-02-27 07:54:42 +03:00
|
|
|
} else {
|
2005-06-28 16:25:34 +04:00
|
|
|
normal_search_cmd (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* toggle ruler */
|
2002-10-31 01:48:59 +03:00
|
|
|
case ALT ('r'):
|
|
|
|
switch (ruler) {
|
1998-02-27 07:54:42 +03:00
|
|
|
case 0:
|
2002-10-31 01:48:59 +03:00
|
|
|
ruler = 1;
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
case 1:
|
2002-10-31 01:48:59 +03:00
|
|
|
ruler = 2;
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
default:
|
2002-10-31 01:48:59 +03:00
|
|
|
ruler = 0;
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
view->dirty++;
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
case 'h':
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_left (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'j':
|
|
|
|
case '\n':
|
|
|
|
case 'e':
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_down (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'd':
|
2005-07-06 23:12:25 +04:00
|
|
|
view_move_down (view, (view->data_area.height + 1) / 2);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'u':
|
2005-07-06 23:12:25 +04:00
|
|
|
view_move_up (view, (view->data_area.height + 1) / 2);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'k':
|
|
|
|
case 'y':
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_up (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'l':
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_right (view, 1);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case ' ':
|
|
|
|
case 'f':
|
2005-07-06 23:12:25 +04:00
|
|
|
view_move_down (view, view->data_area.height);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
case XCTRL ('o'):
|
2001-08-07 20:32:22 +04:00
|
|
|
view_other_cmd ();
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2001-08-07 20:32:22 +04:00
|
|
|
|
2002-10-31 01:48:59 +03:00
|
|
|
/* Unlike Ctrl-O, run a new shell if the subshell is not running. */
|
1998-02-27 07:54:42 +03:00
|
|
|
case '!':
|
|
|
|
exec_shell ();
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'b':
|
2005-07-06 23:12:25 +04:00
|
|
|
view_move_up (view, view->data_area.height);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case KEY_IC:
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_up (view, 2);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case KEY_DC:
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_down (view, 2);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
case 'm':
|
2005-05-21 14:17:35 +04:00
|
|
|
view->marks[view->marker] = view->dpy_topleft;
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
case 'r':
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_topleft = view->marks[view->marker];
|
1998-02-27 07:54:42 +03:00
|
|
|
view->dirty++;
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Use to indicate parent that we want to see the next/previous file */
|
2005-04-16 17:45:16 +04:00
|
|
|
/* Does not work in panel mode */
|
2002-10-31 01:48:59 +03:00
|
|
|
case XCTRL ('f'):
|
|
|
|
case XCTRL ('b'):
|
2005-04-16 17:45:16 +04:00
|
|
|
if (!view_is_in_panel (view))
|
2002-10-31 01:48:59 +03:00
|
|
|
view->move_dir = c == XCTRL ('f') ? 1 : -1;
|
2005-04-16 17:45:16 +04:00
|
|
|
/* FALLTHROUGH */
|
1998-02-27 07:54:42 +03:00
|
|
|
case 'q':
|
2002-10-31 01:48:59 +03:00
|
|
|
case XCTRL ('g'):
|
1998-02-27 07:54:42 +03:00
|
|
|
case ESC_CHAR:
|
|
|
|
if (view_ok_to_quit (view))
|
2005-06-28 02:38:03 +04:00
|
|
|
view->want_to_quit = TRUE;
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2001-06-06 02:49:15 +04:00
|
|
|
#ifdef HAVE_CHARSET
|
2002-10-31 01:48:59 +03:00
|
|
|
case XCTRL ('t'):
|
|
|
|
do_select_codepage ();
|
2001-06-06 02:49:15 +04:00
|
|
|
view->dirty++;
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-31 01:48:59 +03:00
|
|
|
#endif /* HAVE_CHARSET */
|
2001-06-06 02:49:15 +04:00
|
|
|
|
2005-05-26 13:08:54 +04:00
|
|
|
#ifdef MC_ENABLE_DEBUGGING_CODE
|
|
|
|
case 't': /* mnemonic: "test" */
|
|
|
|
view_ccache_dump (view);
|
|
|
|
return MSG_HANDLED;
|
|
|
|
#endif
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
view->marker = c - '0';
|
|
|
|
|
|
|
|
/* Key not used */
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_NOT_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Both views */
|
2002-08-27 23:10:54 +04:00
|
|
|
static int
|
2002-10-31 01:48:59 +03:00
|
|
|
view_event (WView *view, Gpm_Event *event, int *result)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-07-06 23:12:25 +04:00
|
|
|
screen_dimen y, x;
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
*result = MOU_NORMAL;
|
2002-09-21 09:46:19 +04:00
|
|
|
|
|
|
|
/* 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)) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_up (view, 2);
|
2002-09-21 09:46:19 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if ((event->buttons & GPM_B_DOWN) && (event->type & GPM_DOWN)) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_down (view, 2);
|
2002-09-21 09:46:19 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
x = event->x;
|
|
|
|
y = event->y;
|
|
|
|
|
2002-09-21 09:46:19 +04:00
|
|
|
/* Scrolling left and right */
|
2005-04-14 15:14:42 +04:00
|
|
|
if (!view->text_wrap_mode) {
|
2005-07-06 23:12:25 +04:00
|
|
|
if (x < view->data_area.width * 1/4) {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_left (view, 1);
|
2002-09-21 09:46:19 +04:00
|
|
|
goto processed;
|
2005-07-06 23:12:25 +04:00
|
|
|
} else if (x < view->data_area.width * 3/4) {
|
|
|
|
/* ignore the click */
|
|
|
|
} else {
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_right (view, 1);
|
2002-09-21 09:46:19 +04:00
|
|
|
goto processed;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
}
|
2002-09-21 09:46:19 +04:00
|
|
|
|
|
|
|
/* Scrolling up and down */
|
2005-07-06 23:12:25 +04:00
|
|
|
if (y < view->data_area.top + view->data_area.height * 1/3) {
|
2002-09-21 09:46:19 +04:00
|
|
|
if (mouse_move_pages_viewer)
|
2005-07-06 23:12:25 +04:00
|
|
|
view_move_up (view, view->data_area.height / 2);
|
2002-09-21 09:46:19 +04:00
|
|
|
else
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_up (view, 1);
|
2002-09-21 09:46:19 +04:00
|
|
|
goto processed;
|
2005-07-06 23:12:25 +04:00
|
|
|
} else if (y < view->data_area.top + view->data_area.height * 2/3) {
|
|
|
|
/* ignore the click */
|
|
|
|
} else {
|
|
|
|
if (mouse_move_pages_viewer)
|
|
|
|
view_move_down (view, view->data_area.height / 2);
|
2002-09-21 09:46:19 +04:00
|
|
|
else
|
2005-05-26 13:08:54 +04:00
|
|
|
view_move_down (view, 1);
|
2002-09-21 09:46:19 +04:00
|
|
|
goto processed;
|
|
|
|
}
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
return 0;
|
2002-09-21 09:46:19 +04:00
|
|
|
|
|
|
|
processed:
|
|
|
|
*result = MOU_REPEAT;
|
|
|
|
return 1;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Real view only */
|
1998-12-03 00:27:27 +03:00
|
|
|
static int
|
1998-02-27 07:54:42 +03:00
|
|
|
real_view_event (Gpm_Event *event, void *x)
|
|
|
|
{
|
2005-02-08 01:09:44 +03:00
|
|
|
WView *view = (WView *) x;
|
1998-02-27 07:54:42 +03:00
|
|
|
int result;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
2005-02-08 01:09:44 +03:00
|
|
|
if (view_event (view, event, &result))
|
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2002-10-07 22:50:27 +04:00
|
|
|
static void
|
1998-02-27 07:54:42 +03:00
|
|
|
view_adjust_size (Dlg_head *h)
|
|
|
|
{
|
2002-10-31 01:48:59 +03:00
|
|
|
WView *view;
|
1998-02-27 07:54:42 +03:00
|
|
|
WButtonBar *bar;
|
|
|
|
|
|
|
|
/* Look up the viewer and the buttonbar, we assume only two widgets here */
|
2005-06-28 03:19:32 +04:00
|
|
|
view = (WView *) find_widget_type (h, view_callback);
|
2002-11-13 02:33:15 +03:00
|
|
|
bar = find_buttonbar (h);
|
2002-10-31 01:48:59 +03:00
|
|
|
widget_set_size (&view->widget, 0, 0, LINES - 1, COLS);
|
2005-06-14 17:02:30 +04:00
|
|
|
widget_set_size ((Widget *) bar, LINES - 1, 0, 1, COLS);
|
1999-04-06 23:00:16 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
view_compute_areas (view);
|
2002-10-31 01:48:59 +03:00
|
|
|
view_update_bytes_per_line (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2002-09-24 07:56:08 +04:00
|
|
|
/* Callback for the view dialog */
|
2003-09-08 01:24:01 +04:00
|
|
|
static cb_ret_t
|
|
|
|
view_dialog_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
2002-09-24 07:56:08 +04:00
|
|
|
{
|
|
|
|
switch (msg) {
|
|
|
|
case DLG_RESIZE:
|
|
|
|
view_adjust_size (h);
|
|
|
|
return MSG_HANDLED;
|
2003-09-08 01:24:01 +04:00
|
|
|
|
|
|
|
default:
|
|
|
|
return default_dlg_callback (h, msg, parm);
|
2002-09-24 07:56:08 +04:00
|
|
|
}
|
|
|
|
}
|
1998-03-12 06:29:45 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Real view only */
|
|
|
|
int
|
2005-08-01 00:29:35 +04:00
|
|
|
mc_internal_viewer (const char *command, const char *file,
|
|
|
|
int *move_dir_p, int start_line)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-04-17 13:35:41 +04:00
|
|
|
gboolean succeeded;
|
1998-02-27 07:54:42 +03:00
|
|
|
WView *wview;
|
|
|
|
WButtonBar *bar;
|
2002-09-24 07:56:08 +04:00
|
|
|
Dlg_head *view_dlg;
|
2002-09-04 00:19:22 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Create dialog and widgets, put them on the dialog */
|
2002-09-24 07:56:08 +04:00
|
|
|
view_dlg =
|
|
|
|
create_dlg (0, 0, LINES, COLS, NULL, view_dialog_callback,
|
2003-10-24 10:06:10 +04:00
|
|
|
"[Internal File Viewer]", NULL, DLG_WANT_TAB);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-09-04 00:19:22 +04:00
|
|
|
wview = view_new (0, 0, COLS, LINES - 1, 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-09-04 00:19:22 +04:00
|
|
|
bar = buttonbar_new (1);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-09-24 07:56:08 +04:00
|
|
|
add_widget (view_dlg, bar);
|
2003-09-13 02:08:09 +04:00
|
|
|
add_widget (view_dlg, wview);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-07-12 11:01:47 +04:00
|
|
|
succeeded = view_load (wview, command, file, start_line);
|
2005-04-17 13:35:41 +04:00
|
|
|
if (succeeded) {
|
2002-09-24 07:56:08 +04:00
|
|
|
run_dlg (view_dlg);
|
1998-02-27 07:54:42 +03:00
|
|
|
if (move_dir_p)
|
|
|
|
*move_dir_p = wview->move_dir;
|
2005-04-17 13:35:41 +04:00
|
|
|
} else {
|
|
|
|
if (move_dir_p)
|
|
|
|
*move_dir_p = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2002-09-24 07:56:08 +04:00
|
|
|
destroy_dlg (view_dlg);
|
2002-09-04 00:19:22 +04:00
|
|
|
|
2005-04-17 13:35:41 +04:00
|
|
|
return succeeded;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
view_hook (void *v)
|
|
|
|
{
|
|
|
|
WView *view = (WView *) v;
|
|
|
|
WPanel *panel;
|
|
|
|
|
|
|
|
/* If the user is busy typing, wait until he finishes to update the
|
|
|
|
screen */
|
2002-10-31 01:48:59 +03:00
|
|
|
if (!is_idle ()) {
|
1998-02-27 07:54:42 +03:00
|
|
|
if (!hook_present (idle_hook, view_hook))
|
|
|
|
add_hook (&idle_hook, view_hook, v);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete_hook (&idle_hook, view_hook);
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
if (get_current_type () == view_listing)
|
2003-10-26 09:45:59 +03:00
|
|
|
panel = current_panel;
|
1998-02-27 07:54:42 +03:00
|
|
|
else if (get_other_type () == view_listing)
|
|
|
|
panel = other_panel;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
2005-04-14 12:00:14 +04:00
|
|
|
view_load (view, 0, panel->dir.list[panel->selected].fname, 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
display (view);
|
|
|
|
}
|
|
|
|
|
2003-09-11 02:48:54 +04:00
|
|
|
static cb_ret_t
|
2005-06-28 03:19:32 +04:00
|
|
|
view_callback (Widget *w, widget_msg_t msg, int parm)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-06-28 03:19:32 +04:00
|
|
|
WView *view = (WView *) w;
|
2003-09-11 02:48:54 +04:00
|
|
|
cb_ret_t i;
|
2002-11-13 05:27:00 +03:00
|
|
|
Dlg_head *h = view->widget.parent;
|
2002-10-07 22:50:27 +04:00
|
|
|
|
2005-07-06 23:12:25 +04:00
|
|
|
view_compute_areas (view);
|
2005-01-26 01:40:50 +03:00
|
|
|
view_update_bytes_per_line (view);
|
|
|
|
|
2002-10-07 22:50:27 +04:00
|
|
|
switch (msg) {
|
1998-02-27 07:54:42 +03:00
|
|
|
case WIDGET_INIT:
|
2005-04-16 17:45:16 +04:00
|
|
|
if (view_is_in_panel (view))
|
1998-02-27 07:54:42 +03:00
|
|
|
add_hook (&select_file_hook, view_hook, view);
|
|
|
|
else
|
|
|
|
view_labels (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-07 22:50:27 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
case WIDGET_DRAW:
|
|
|
|
display (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
case WIDGET_CURSOR:
|
|
|
|
if (view->hex_mode)
|
|
|
|
view_place_cursor (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
case WIDGET_KEY:
|
2003-09-11 02:48:54 +04:00
|
|
|
i = view_handle_key ((WView *) view, parm);
|
2005-06-28 02:38:03 +04:00
|
|
|
if (view->want_to_quit && !view_is_in_panel (view))
|
1998-03-14 03:42:23 +03:00
|
|
|
dlg_stop (h);
|
1998-02-27 07:54:42 +03:00
|
|
|
else {
|
2005-02-08 01:09:44 +03:00
|
|
|
view_update (view);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
return i;
|
|
|
|
|
|
|
|
case WIDGET_FOCUS:
|
|
|
|
view_labels (view);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2002-10-07 22:50:27 +04:00
|
|
|
|
2003-09-10 22:21:40 +04:00
|
|
|
case WIDGET_DESTROY:
|
|
|
|
view_done (view);
|
2005-04-16 17:45:16 +04:00
|
|
|
if (view_is_in_panel (view))
|
2003-09-10 22:21:40 +04:00
|
|
|
delete_hook (&select_file_hook, view_hook);
|
2003-09-11 02:48:54 +04:00
|
|
|
return MSG_HANDLED;
|
2003-09-10 22:21:40 +04:00
|
|
|
|
|
|
|
default:
|
2003-09-11 02:48:54 +04:00
|
|
|
return default_proc (msg, parm);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WView *
|
|
|
|
view_new (int y, int x, int cols, int lines, int is_panel)
|
|
|
|
{
|
2001-06-25 15:24:49 +04:00
|
|
|
WView *view = g_new0 (WView, 1);
|
2005-08-15 22:58:18 +04:00
|
|
|
size_t i;
|
2002-10-31 01:48:59 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
init_widget (&view->widget, y, x, lines, cols,
|
2005-06-28 03:19:32 +04:00
|
|
|
view_callback,
|
|
|
|
real_view_event);
|
2005-04-14 12:00:14 +04:00
|
|
|
widget_want_cursor (view->widget, 0);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-04-14 12:00:14 +04:00
|
|
|
view->filename = NULL;
|
|
|
|
view->command = NULL;
|
|
|
|
|
|
|
|
view_set_datasource_none (view);
|
|
|
|
|
2005-08-15 22:58:18 +04:00
|
|
|
view->growbuf_in_use = FALSE;
|
|
|
|
/* leave the other growbuf fields uninitialized */
|
|
|
|
|
|
|
|
view->hex_mode = default_hex_mode;
|
|
|
|
view->hexedit_mode = default_hexedit_mode;
|
|
|
|
view->hexview_in_text = FALSE;
|
|
|
|
view->text_nroff_mode = default_nroff_flag;
|
|
|
|
view->text_wrap_mode = global_wrap_mode;
|
|
|
|
view->magic_mode = default_magic_flag;
|
|
|
|
|
|
|
|
view->hexedit_lownibble = FALSE;
|
|
|
|
view->coord_cache = NULL;
|
|
|
|
|
2005-04-16 17:45:16 +04:00
|
|
|
view->dpy_frame_size = is_panel ? 1 : 0;
|
2005-05-21 14:17:35 +04:00
|
|
|
view->dpy_topleft = 0;
|
|
|
|
view->dpy_text_column = 0;
|
2005-08-15 22:58:18 +04:00
|
|
|
view->dpy_complete = FALSE;
|
2005-05-21 14:23:57 +04:00
|
|
|
view->hex_cursor = 0;
|
2005-04-14 12:00:14 +04:00
|
|
|
view->cursor_col = 0;
|
|
|
|
view->cursor_row = 0;
|
|
|
|
view->change_list = NULL;
|
2005-08-15 22:58:18 +04:00
|
|
|
|
|
|
|
/* {status,ruler,data}_area are left uninitialized */
|
|
|
|
|
2005-04-14 12:00:14 +04:00
|
|
|
view->dirty = 0;
|
|
|
|
view->bytes_per_line = 1;
|
|
|
|
|
|
|
|
view->search_start = 0;
|
|
|
|
view->found_len = 0;
|
|
|
|
view->search_exp = NULL;
|
|
|
|
view->direction = 1; /* forward */
|
|
|
|
view->last_search = 0; /* it's a function */
|
|
|
|
|
2005-06-28 02:38:03 +04:00
|
|
|
view->want_to_quit = FALSE;
|
2005-04-14 12:00:14 +04:00
|
|
|
view->marker = 0;
|
2005-08-15 22:58:18 +04:00
|
|
|
for (i = 0; i < sizeof(view->marks) / sizeof(view->marks[0]); i++)
|
|
|
|
view->marks[i] = 0;
|
|
|
|
|
2005-04-14 12:00:14 +04:00
|
|
|
view->move_dir = 0;
|
|
|
|
view->update_steps = 0;
|
|
|
|
view->update_activate = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|