1 /* {{{ Copyright notice */
3 /* View file module for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996 The Free Software Foundation
5 Written by: 1994, 1995, 1998 Miguel de Icaza
6 1994, 1995 Janne Kukonlehto
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 /* {{{ Declarations */
30 #include <sys/types.h>
37 # include <sys/mman.h>
40 #include <ctype.h> /* For toupper() */
46 #include "cmd.h" /* For view_other_cmd */
47 #include "dlg.h" /* Needed by widget.h */
48 #include "widget.h" /* Needed for buttonbar_new */
53 #include "key.h" /* For mi_getch() */
56 #include "wtools.h" /* For query_set_sel() */
57 #include "../vfs/vfs.h"
59 #include "panel.h" /* Needed for current_panel and other_panel */
61 #include "main.h" /* For the externs */
67 #include "selcodepage.h"
68 #endif /* HAVE_CHARSET */
74 /* Block size for reading files in parts */
75 #define READ_BLOCK 8192
76 #define VIEW_PAGE_SIZE 8192
79 # define IFAIX(x) case (x):
84 /* Maxlimit for skipping updates */
85 static int max_dirt_limit
=
92 extern Hook
*idle_hook
;
94 /* If set, show a ruler */
97 /* Scrolling is done in pages or line increments */
98 int mouse_move_pages_viewer
= 1;
100 /* Used to compute the bottom first variable */
101 int have_fast_cpu
= 0;
103 /* wrap mode default */
104 int global_wrap_mode
= 1;
106 int default_hex_mode
= 0;
107 static int default_hexedit_mode
= 0;
108 int default_magic_flag
= 1;
109 int default_nroff_flag
= 1;
110 int altered_hex_mode
= 0;
111 int altered_magic_flag
= 0;
112 int altered_nroff_flag
= 0;
117 static const char hex_char
[] = "0123456789ABCDEF";
120 static int view_callback (Dlg_head
*h
, WView
*view
, int msg
, int par
);
122 static int regexp_view_search (WView
*view
, char *pattern
, char *string
, int match_type
);
123 static void view_move_forward (WView
*view
, int i
);
124 static void view_labels (WView
*view
);
125 static void set_monitor (WView
*view
, int set_on
);
126 static void view_update (WView
*view
, gboolean update_gui
);
129 /* {{{ Clean-up functions */
132 close_view_file (WView
*view
)
134 if (view
->file
!= -1){
135 mc_close (view
->file
);
141 free_file (WView
*view
)
147 mc_munmap (view
->data
, view
->s
.st_size
);
148 close_view_file (view
);
150 #endif /* HAVE_MMAP */
152 if (view
->reading_pipe
){
153 /* Check error messages */
154 if (!view
->have_frame
)
158 pclose (view
->stdfile
);
159 view
->stdfile
= NULL
;
161 /* Ignore errors because we don't want to hear about broken pipe */
162 close_error_pipe (-1, NULL
);
164 close_view_file (view
);
166 /* Block_ptr may be zero if the file was a file with 0 bytes */
167 if (view
->growing_buffer
&& view
->block_ptr
){
168 for (i
= 0; i
< view
->blocks
; i
++){
169 g_free (view
->block_ptr
[i
].data
);
171 g_free (view
->block_ptr
);
175 /* Valid parameters for second parameter to set_monitor */
180 view_done (WView
*view
)
182 set_monitor (view
, off
);
184 /* alex: release core, used to replace mmap */
185 if (!view
->mmapping
&& !view
->growing_buffer
&& view
->data
!= NULL
){
190 if (view
->view_active
){
192 mc_ungetlocalcopy (view
->filename
, view
->localcopy
, 0);
194 g_free (view
->filename
);
196 g_free (view
->command
);
198 view
->view_active
= 0;
199 default_hex_mode
= view
->hex_mode
;
200 default_nroff_flag
= view
->viewer_nroff_flag
;
201 default_magic_flag
= view
->viewer_magic_flag
;
202 global_wrap_mode
= view
->wrap_mode
;
205 static void view_hook (void *);
208 view_destroy (WView
*view
)
211 if (view
->have_frame
)
212 delete_hook (&select_file_hook
, view_hook
);
216 get_byte (WView
*view
, unsigned int byte_index
)
218 int page
= byte_index
/ VIEW_PAGE_SIZE
+ 1;
219 int offset
= byte_index
% VIEW_PAGE_SIZE
;
222 if (view
->growing_buffer
){
223 if (page
> view
->blocks
){
224 view
->block_ptr
= g_realloc (view
->block_ptr
,
225 sizeof (block_ptr_t
) * page
);
226 for (i
= view
->blocks
; i
< page
; i
++){
227 char *p
= g_malloc (VIEW_PAGE_SIZE
);
228 view
->block_ptr
[i
].data
= p
;
231 if (view
->stdfile
!= NULL
)
232 n
= fread (p
, 1, VIEW_PAGE_SIZE
, view
->stdfile
);
234 n
= mc_read (view
->file
, p
, VIEW_PAGE_SIZE
);
236 * FIXME: Errors are ignored at this point
237 * Also should report preliminary EOF
240 view
->bytes_read
+= n
;
241 if (view
->s
.st_size
< view
->bytes_read
){
242 view
->bottom_first
= -1; /* Invalidate cache */
243 view
->s
.st_size
= view
->bytes_read
;
244 view
->last_byte
= view
->bytes_read
;
245 if (view
->reading_pipe
)
246 view
->last_byte
= view
->first
+ view
->bytes_read
;
248 /* To force loading the next page */
249 if (n
== VIEW_PAGE_SIZE
&& view
->reading_pipe
){
255 if (byte_index
> view
->bytes_read
){
258 return view
->block_ptr
[page
-1].data
[offset
];
260 if (byte_index
>= view
->last_byte
)
263 return view
->data
[byte_index
];
268 enqueue_change (struct hexedit_change_node
**head
, struct hexedit_change_node
*node
)
270 struct hexedit_change_node
*curr
= *head
;
273 if (node
->offset
< curr
->offset
) {
278 head
= (struct hexedit_change_node
**) curr
;
285 static void move_right (WView
*);
288 put_editkey (WView
*view
, unsigned char key
)
290 struct hexedit_change_node
*node
;
291 unsigned char byte_val
;
293 if (!view
->hexedit_mode
|| view
->growing_buffer
!= 0)
296 /* Has there been a change at this position ? */
297 node
= view
->change_list
;
298 while (node
&& (node
->offset
!= view
->edit_cursor
)) {
302 if (view
->view_side
== view_side_left
) {
305 if (key
>= '0' && key
<= '9')
307 else if (key
>= 'A' && key
<= 'F')
309 else if (key
>= 'a' && key
<= 'f')
315 byte_val
= node
->value
;
317 byte_val
= get_byte(view
, view
->edit_cursor
);
319 if (view
->nib_shift
== 0) {
320 byte_val
= (byte_val
& 0x0f) | (key
<< 4);
322 byte_val
= (byte_val
& 0xf0) | (key
);
329 node
= (struct hexedit_change_node
*)
330 g_new (struct hexedit_change_node
, 1);
334 /* alex@bcs.zaporizhzhe.ua: here we are using file copy
335 * completely loaded into memory, so we can replace bytes in
336 * view->data array to allow changes to be reflected when
337 * user switches back to ascii mode */
338 view
->data
[view
->edit_cursor
] = byte_val
;
339 #endif /* !HAVE_MMAP */
340 node
->offset
= view
->edit_cursor
;
341 node
->value
= byte_val
;
342 enqueue_change (&view
->change_list
, node
);
345 node
->value
= byte_val
;
348 view_update (view
, TRUE
);
353 free_change_list (WView
*view
)
355 struct hexedit_change_node
*n
= view
->change_list
;
358 view
->change_list
= n
->next
;
360 n
= view
->change_list
;
362 view
->file_dirty
= 0;
367 save_edit_changes (WView
*view
)
369 struct hexedit_change_node
*node
= view
->change_list
;
373 fp
= open (view
->filename
, O_WRONLY
);
376 if (lseek (fp
, node
->offset
, SEEK_SET
) == -1 ||
377 write (fp
, &node
->value
, 1) != 1) {
388 fp
= query_dialog (_(" Save file "),
389 _(" Error trying to save file. "),
390 2, 2, _("&Retry"), _("&Cancel"));
396 free_change_list (view
);
400 view_ok_to_quit (WView
*view
)
405 if (!view
->change_list
)
409 text
= g_strconcat (_("File: \n\n "), view
->filename
,
410 _("\n\nhas been modified, do you want to save the changes?\n"), NULL
);
412 r
= query_dialog (_(" Save changes "), text
, 2, 3, _("&Yes"), _("&No"), _("&Cancel"));
417 save_edit_changes (view
);
420 free_change_list (view
);
428 set_view_init_error (WView
*view
, char *msg
)
430 view
->growing_buffer
= 0;
431 view
->reading_pipe
= 0;
435 view
->bytes_read
= strlen (msg
);
436 return g_strdup (msg
);
441 /* return values: NULL for success, else points to error message */
443 init_growing_view (WView
* view
, char *name
, char *filename
)
445 char *err_msg
= NULL
;
447 view
->growing_buffer
= 1;
450 view
->reading_pipe
= 1;
454 if ((view
->stdfile
= popen (name
, "r")) == NULL
) {
455 /* Avoid two messages. Message from stderr has priority. */
456 if (!close_error_pipe (view
->have_frame
? -1 : 1, view
->data
))
457 err_msg
= _(" Cannot spawn child program ");
458 return set_view_init_error (view
, err_msg
);
461 /* First, check if filter produced any output */
463 if (view
->bytes_read
<= 0) {
464 pclose (view
->stdfile
);
465 view
->stdfile
= NULL
;
466 /* Avoid two messages. Message from stderr has priority. */
467 if (!close_error_pipe (view
->have_frame
? -1 : 1, view
->data
))
468 err_msg
= (" Empty output from child filter ");
469 return set_view_init_error (view
, err_msg
);
472 view
->stdfile
= NULL
;
473 if ((view
->file
= mc_open (filename
, O_RDONLY
)) == -1)
474 return set_view_init_error (view
, _(" Could not open file "));
479 /* Load filename into core */
482 if (have_frame), we return success, but data points to a
483 error message instead of the file buffer (quick_view feature).
485 static char *load_view_file (WView
*view
, int fd
)
489 if (view
->s
.st_size
== 0){
490 /* Must be one of those nice files that grow (/proc) */
491 close_view_file (view
);
492 return init_growing_view (view
, 0, view
->filename
);
496 view
->data
= mc_mmap (0, view
->s
.st_size
, PROT_READ
, MAP_FILE
| MAP_SHARED
,
498 if ((caddr_t
) view
->data
!= (caddr_t
) -1) {
501 view
->bytes_read
= view
->s
.st_size
;
505 #endif /* HAVE_MMAP */
507 /* For those OS that dont provide mmap call. Try to load all the
508 * file into memory (alex@bcs.zaporizhzhe.ua). Also, mmap can fail
509 * for any reason, so we use this as fallback (pavel@ucw.cz) */
511 view
->data
= (unsigned char*) g_malloc (view
->s
.st_size
);
512 if (view
->data
== NULL
513 || mc_lseek(view
->file
, 0, SEEK_SET
) != 0
514 || mc_read(view
->file
, view
->data
, view
->s
.st_size
) != view
->s
.st_size
){
515 if (view
->data
!= NULL
)
517 close_view_file (view
);
518 return init_growing_view (view
, 0, view
->filename
);
521 view
->bytes_read
= view
->s
.st_size
;
525 /* Return zero on success, -1 on failure */
527 do_view_init (WView
*view
, char *_command
, const char *_file
, int start_line
)
532 char tmp
[BUF_MEDIUM
];
534 if (view
->view_active
)
537 /* Set up the state */
540 view
->growing_buffer
= 0;
541 view
->reading_pipe
= 0;
545 view
->first
= view
->bytes_read
= 0;
547 view
->filename
= g_strdup (_file
);
550 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
552 /* Clear the markers */
554 for (i
= 0; i
< 10; i
++)
557 if (!view
->have_frame
){
561 if (_command
&& (view
->viewer_magic_flag
|| _file
[0] == '\0')) {
562 error
= init_growing_view (view
, _command
, view
->filename
);
563 } else if (_file
[0]) {
564 /* Make sure we are working with a regular file */
565 if (mc_stat (view
->filename
, &view
->s
) == -1) {
566 g_snprintf (tmp
, sizeof (tmp
), _(" Cannot stat \"%s\"\n %s "),
567 _file
, unix_error_string (errno
));
568 error
= set_view_init_error (view
, tmp
);
572 if (!S_ISREG (view
->s
.st_mode
)) {
573 g_snprintf (tmp
, sizeof (tmp
),
574 _(" Cannot view: not a regular file "));
575 error
= set_view_init_error (view
, tmp
);
579 /* Actually open the file */
580 if ((fd
= mc_open(_file
, O_RDONLY
)) == -1) {
581 g_snprintf (tmp
, sizeof (tmp
), _(" Cannot open \"%s\"\n %s "),
582 _file
, unix_error_string (errno
));
583 error
= set_view_init_error (view
, tmp
);
587 type
= get_compression_type (fd
);
589 if (view
->viewer_magic_flag
&& (type
!= COMPRESSION_NONE
)) {
590 g_free (view
->filename
);
591 view
->filename
= g_strconcat (_file
, decompress_extension(type
), NULL
);
594 error
= load_view_file (view
, fd
);
599 if (!view
->have_frame
){
600 message (1, MSG_ERROR
, "%s", error
);
606 view
->view_active
= 1;
608 view
->command
= g_strdup (_command
);
611 view
->search_start
= view
->start_display
= view
->start_save
= view
->first
;
614 view
->last_search
= 0; /* Start a new search */
616 /* Special case: The data points to the error message */
620 view
->s
.st_size
= view
->bytes_read
= strlen (view
->data
);
622 view
->last_byte
= view
->first
+ view
->s
.st_size
;
624 if (start_line
> 1 && !error
){
625 int saved_wrap_mode
= view
->wrap_mode
;
629 view_move_forward (view
, start_line
- 1);
630 view
->wrap_mode
= saved_wrap_mode
;
632 view
->edit_cursor
= view
->first
;
633 view
->file_dirty
= 0;
635 view
->view_side
= view_side_left
;
636 view
->change_list
= NULL
;
642 view_update_bytes_per_line(WView
*view
)
646 if (view
->have_frame
)
647 cols
= view
->widget
.cols
- 2;
649 cols
= view
->widget
.cols
;
651 view
->bottom_first
= -1;
652 view
->bytes_per_line
= ((2 * (cols
- 8) / 9) & 0xfffc);
654 if (view
->bytes_per_line
== 0)
655 view
->bytes_per_line
++; /* To avoid division by 0 */
657 view
->dirty
= max_dirt_limit
+ 1; /* To force refresh */
661 /* Return zero on success, -1 on failure */
663 view_init (WView
*view
, char *_command
, const char *_file
, int start_line
)
665 view_update_bytes_per_line(view
);
667 if (!view
->view_active
|| strcmp (_file
, view
->filename
) || altered_magic_flag
)
668 return do_view_init (view
, _command
, _file
, start_line
);
675 /* {{{ Screen update functions */
678 view_percent (WView
*view
, int p
, int w
, gboolean update_gui
)
682 percent
= (view
->s
.st_size
== 0 || view
->last_byte
== view
->last
) ? 100 :
684 p
/ (view
->s
.st_size
/ 100) :
685 p
* 100 / view
->s
.st_size
);
688 percent
= view
->s
.st_size
== 0 ? 100 :
689 (view
->last_byte
== view
->last
? 100 :
690 (p
)*100 / view
->s
.st_size
);
693 widget_move (view
, view
->have_frame
, w
- 5);
694 printw ("%3d%%", percent
);
698 view_status (WView
*view
, gboolean update_gui
)
700 static int i18n_adjust
=0;
701 static char *file_label
;
703 int w
= view
->widget
.cols
- (view
->have_frame
* 2);
706 attrset (SELECTED_COLOR
);
707 widget_move (view
, view
->have_frame
, view
->have_frame
);
711 file_label
= _("File: %s");
712 i18n_adjust
= strlen(file_label
) - 2;
715 if (w
< i18n_adjust
+ 6)
716 addstr (name_trunc (view
->filename
? view
->filename
:
717 view
->command
? view
->command
:"", w
));
719 i
= (w
> 22 ? 22 : w
) - i18n_adjust
;
720 printw (file_label
, name_trunc (view
->filename
? view
->filename
:
721 view
->command
? view
->command
:"", i
));
723 widget_move (view
, view
->have_frame
, 24 + view
->have_frame
);
725 printw (_("Offset 0x%08x"), view
->edit_cursor
);
727 printw (_("Col %d"), -view
->start_col
);
730 widget_move (view
, view
->have_frame
, 43 + view
->have_frame
);
731 printw (_("%s bytes"), size_trunc (view
->s
.st_size
));
735 if (view
->growing_buffer
)
736 addstr (_(" [grow]"));
740 view
->hex_mode
? view
->edit_cursor
: view
->start_display
,
741 view
->widget
.cols
- view
->have_frame
+ 1,
745 attrset (SELECTED_COLOR
);
749 view_display_clean (WView
*view
, int height
, int width
)
751 /* FIXME: Should I use widget_erase only and repaint the box? */
752 if (view
->have_frame
){
755 draw_double_box (view
->widget
.parent
, view
->widget
.y
, view
->widget
.x
,
756 view
->widget
.lines
, view
->widget
.cols
);
757 for (i
= 1; i
< height
; i
++){
758 widget_move (view
, i
, 1);
759 printw ("%*s", width
-1, "");
762 widget_erase ((Widget
*) view
);
765 #define view_add_character(view,c) addch (c)
766 #define view_add_one_vline() one_vline()
767 #define view_add_string(view,s) addstr (s)
768 #define view_gotoyx(v,r,c) widget_move (v,r,c)
770 #define view_freeze(view)
771 #define view_thaw(view)
773 #define STATUS_LINES 1
782 /* Shows the file pointed to by *start_display on view_win */
784 display (WView
* view
)
786 const int frame_shift
= view
->have_frame
;
787 int col
= 0 + frame_shift
;
788 int row
= STATUS_LINES
+ frame_shift
;
792 mark_t boldflag
= MARK_NORMAL
;
793 struct hexedit_change_node
*curr
= view
->change_list
;
795 height
= view
->widget
.lines
- frame_shift
;
796 width
= view
->widget
.cols
- frame_shift
;
797 from
= view
->start_display
;
798 attrset (NORMAL_COLOR
);
801 view_display_clean (view
, height
, width
);
803 /* Optionally, display a ruler */
804 if ((!view
->hex_mode
) && (ruler
)) {
808 attrset (MARKED_COLOR
);
809 for (c
= frame_shift
; c
< width
; c
++) {
810 cl
= c
- view
->start_col
;
812 view_gotoyx (view
, row
, c
);
814 view_gotoyx (view
, row
+ height
- 2, c
);
818 else if ((cl
% 5) == 0)
820 view_add_character (view
, r_buff
[0]);
821 if ((cl
!= 0) && (cl
% 10) == 0) {
822 g_snprintf (r_buff
, sizeof (r_buff
), "%03d", cl
);
824 widget_move (view
, row
+ 1, c
- 1);
826 widget_move (view
, row
+ height
- 3, c
- 1);
828 view_add_string (view
, r_buff
);
831 attrset (NORMAL_COLOR
);
838 /* Find the first displayable changed byte */
839 while (curr
&& (curr
->offset
< from
)) {
842 if (view
->hex_mode
) {
843 char hex_buff
[10]; /* A temporary buffer for sprintf and mvwaddstr */
844 int bytes
; /* Number of bytes already printed on the line */
846 /* Start of text column */
847 int text_start
= width
- view
->bytes_per_line
- 1 + frame_shift
;
849 for (; row
< height
&& from
< view
->last_byte
; row
++) {
850 /* Print the hex offset */
851 attrset (MARKED_COLOR
);
852 g_snprintf (hex_buff
, sizeof (hex_buff
), "%08X",
853 (int) (from
- view
->first
));
854 view_gotoyx (view
, row
, frame_shift
);
855 view_add_string (view
, hex_buff
);
856 attrset (NORMAL_COLOR
);
858 /* Hex dump starts from column nine */
861 /* Each hex number is two digits */
864 bytes
< view
->bytes_per_line
&& from
< view
->last_byte
;
866 /* Display and mark changed bytes */
867 if (curr
&& from
== curr
->offset
) {
870 boldflag
= MARK_CHANGED
;
871 attrset (VIEW_UNDERLINED_COLOR
);
873 c
= (unsigned char) get_byte (view
, from
);
875 if (view
->found_len
&& from
>= view
->search_start
876 && from
< view
->search_start
+ view
->found_len
) {
877 boldflag
= MARK_SELECTED
;
878 attrset (MARKED_COLOR
);
880 /* Display the navigation cursor */
881 if (from
== view
->edit_cursor
) {
882 if (view
->view_side
== view_side_left
) {
883 view
->cursor_row
= row
;
884 view
->cursor_col
= col
;
886 boldflag
= MARK_CURSOR
;
887 attrset (view
->view_side
==
888 view_side_left
? VIEW_UNDERLINED_COLOR
:
889 MARKED_SELECTED_COLOR
);
892 /* Print a hex number (sprintf is too slow) */
893 hex_buff
[0] = hex_char
[(c
>> 4)];
894 hex_buff
[1] = hex_char
[c
& 15];
895 view_gotoyx (view
, row
, col
);
896 view_add_string (view
, hex_buff
);
898 /* Turn off the cursor or changed byte highlighting here */
899 if (boldflag
== MARK_CURSOR
|| boldflag
== MARK_CHANGED
)
900 attrset (NORMAL_COLOR
);
901 if ((bytes
& 3) == 3 && bytes
+ 1 < view
->bytes_per_line
) {
902 /* Turn off the search highlighting */
903 if (boldflag
== MARK_SELECTED
905 view
->search_start
+ view
->found_len
- 1)
906 attrset (NORMAL_COLOR
);
908 /* Hex numbers are printed in the groups of four */
909 /* Groups are separated by a vline */
911 view_gotoyx (view
, row
, col
- 1);
912 view_add_character (view
, ' ');
913 view_gotoyx (view
, row
, col
);
914 view_add_one_vline ();
917 if (boldflag
!= MARK_NORMAL
919 view
->search_start
+ view
->found_len
- 1)
920 attrset (MARKED_COLOR
);
923 if (boldflag
!= MARK_NORMAL
924 && from
< view
->search_start
+ view
->found_len
- 1
925 && bytes
!= view
->bytes_per_line
- 1) {
926 view_gotoyx (view
, row
, col
);
927 view_add_character (view
, ' ');
930 /* Print the corresponding ascii character */
931 view_gotoyx (view
, row
, text_start
+ bytes
);
937 if (!is_printable (c
))
943 attrset (MARKED_COLOR
);
946 if (view
->view_side
== view_side_right
) {
947 /* Our side is active */
948 view
->cursor_col
= text_start
+ bytes
;
949 view
->cursor_row
= row
;
950 attrset (VIEW_UNDERLINED_COLOR
);
952 /* Other side is active */
953 attrset (MARKED_SELECTED_COLOR
);
957 attrset (VIEW_UNDERLINED_COLOR
);
960 view_add_character (view
, c
);
962 if (boldflag
!= MARK_NORMAL
) {
963 boldflag
= MARK_NORMAL
;
964 attrset (NORMAL_COLOR
);
969 if (view
->growing_buffer
&& from
== view
->last_byte
)
970 get_byte (view
, from
);
971 for (; row
< height
&& from
< view
->last_byte
; from
++) {
972 c
= get_byte (view
, from
);
973 if ((c
== '\n') || (col
== width
&& view
->wrap_mode
)) {
976 if (c
== '\n' || row
>= height
)
982 col
= ((col
- frame_shift
) / 8) * 8 + 8 + frame_shift
;
985 if (view
->viewer_nroff_flag
&& c
== '\b') {
989 if (from
+ 1 < view
->last_byte
990 && is_printable ((c_next
= get_byte (view
, from
+ 1)))
991 && from
> view
->first
992 && is_printable ((c_prev
= get_byte (view
, from
- 1)))
993 && (c_prev
== c_next
|| c_prev
== '_')) {
994 if (col
<= frame_shift
) {
995 /* So it has to be wrap_mode - do not need to check for it */
996 if (row
== 1 + frame_shift
) {
998 continue; /* There had to be a bold character on the rightmost position
999 of the previous undisplayed line */
1005 boldflag
= MARK_SELECTED
;
1006 if (c_prev
== '_' && c_next
!= '_')
1007 attrset (VIEW_UNDERLINED_COLOR
);
1009 attrset (MARKED_COLOR
);
1013 if (view
->found_len
&& from
>= view
->search_start
1014 && from
< view
->search_start
+ view
->found_len
) {
1015 boldflag
= MARK_SELECTED
;
1016 attrset (SELECTED_COLOR
);
1018 if (col
>= frame_shift
- view
->start_col
1019 && col
< width
- view
->start_col
) {
1020 view_gotoyx (view
, row
, col
+ view
->start_col
);
1026 if (!is_printable (c
))
1029 view_add_character (view
, c
);
1032 if (boldflag
!= MARK_NORMAL
) {
1033 boldflag
= MARK_NORMAL
;
1034 attrset (NORMAL_COLOR
);
1037 /* Very last thing */
1038 if (view
->growing_buffer
&& from
+ 1 == view
->last_byte
)
1039 get_byte (view
, from
+ 1);
1048 view_place_cursor (WView
*view
)
1052 if (view
->view_side
== view_side_left
)
1053 shift
= view
->nib_shift
;
1057 widget_move (&view
->widget
, view
->cursor_row
, view
->cursor_col
+ shift
);
1061 view_update (WView
*view
, gboolean update_gui
)
1063 static int dirt_limit
= 1;
1065 if (view
->dirty
> dirt_limit
){
1066 /* Too many updates skipped -> force a update */
1068 view_status (view
, update_gui
);
1070 /* Raise the update skipping limit */
1072 if (dirt_limit
> max_dirt_limit
)
1073 dirt_limit
= max_dirt_limit
;
1077 /* We have time to update the screen properly */
1079 view_status (view
, update_gui
);
1084 /* We are busy -> skipping full update,
1085 only the status line is updated */
1086 view_status (view
, update_gui
);
1088 /* Here we had a refresh, if fast scrolling does not work
1089 restore the refresh, although this should not happen */
1094 my_define (Dlg_head
*h
, int idx
, char *text
,
1095 void (*fn
)(WView
*), WView
*view
)
1097 define_label_data (h
, (Widget
*) view
, idx
, text
, (buttonbarfn
) fn
, view
);
1101 /* {{{ Movement functions */
1102 /* If the last parameter is nonzero, it means we want get the count of lines
1103 from current up to the the upto position inclusive */
1105 move_forward2 (WView
*view
, long current
, int lines
, long upto
)
1111 if (view
->hex_mode
){
1112 p
= current
+ lines
* view
->bytes_per_line
;
1113 p
= (p
>= view
->last_byte
) ? current
: p
;
1115 q
= view
->edit_cursor
+ view
->bytes_per_line
;
1116 line
= q
/ view
->bytes_per_line
;
1117 col
= (view
->last_byte
-1) / view
->bytes_per_line
;
1118 view
->edit_cursor
= (line
> col
) ? view
->edit_cursor
: q
;
1119 view
->edit_cursor
= (view
->edit_cursor
< view
->last_byte
) ?
1120 view
->edit_cursor
: view
->last_byte
-1;
1121 q
= current
+ ((LINES
-2) * view
->bytes_per_line
);
1122 p
= (view
->edit_cursor
< q
) ? current
: p
;
1124 view
->edit_cursor
= (view
->edit_cursor
< p
) ?
1125 p
: view
->edit_cursor
;
1133 q
= view
->last_byte
;
1134 if (get_byte (view
, q
) != '\n')
1136 for (line
= col
= 0, p
= current
; p
< q
; p
++){
1139 if (lines
!= -1 && line
>= lines
)
1142 c
= get_byte (view
, p
);
1144 if (view
->wrap_mode
){
1146 continue; /* This characters is never displayed */
1148 col
= ((col
- view
->have_frame
)/8)*8 +8+ view
->have_frame
;
1151 if (view
->viewer_nroff_flag
&& c
== '\b'){
1152 if (p
+ 1 < view
->last_byte
1153 && is_printable (get_byte (view
, p
+ 1))
1155 && is_printable (get_byte (view
, p
- 1)))
1157 } else if (col
== vwidth
){
1158 /* FIXME: the c in is_printable was a p, that is a bug,
1159 I suspect I got that fix from Jakub, same applies
1161 int d
= get_byte (view
, p
+2);
1163 if (p
+ 2 >= view
->last_byte
|| !is_printable (c
) ||
1164 !view
->viewer_nroff_flag
|| get_byte (view
, p
+ 1) != '\b' ||
1168 if (c
== '\n' || get_byte (view
, p
+1) != '\n')
1171 } else if (c
== '\n'){
1175 } else if (c
== '\n')
1184 /* returns the new current pointer */
1185 /* Cause even the forward routine became very complex, we in the wrap_mode
1186 just find the nearest '\n', use move_forward2(p, 0, q) to get the count
1187 of lines up to there and then use move_forward2(p, something, 0), which we
1190 move_backward2 (WView
*view
, unsigned long current
, int lines
)
1195 if (!view
->hex_mode
&& current
== view
->first
)
1198 if (view
->hex_mode
){
1199 p
= current
- lines
* view
->bytes_per_line
;
1200 p
= (p
< view
->first
) ? view
->first
: p
;
1202 q
= view
->edit_cursor
- view
->bytes_per_line
;
1203 view
->edit_cursor
= (q
< view
->first
) ? view
->edit_cursor
: q
;
1204 p
= (view
->edit_cursor
>= current
) ? current
: p
;
1206 q
= p
+ ((LINES
-2) * view
->bytes_per_line
);
1207 view
->edit_cursor
= (view
->edit_cursor
>= q
) ?
1208 p
: view
->edit_cursor
;
1212 if (current
== view
->last_byte
1213 && get_byte (view
, current
- 1) != '\n')
1214 /* There is one virtual '\n' at the end,
1215 so that the last line is shown */
1219 for (q
= p
= current
- 1; p
>= view
->first
; p
--)
1220 if (get_byte (view
, p
) == '\n' || p
== view
->first
) {
1221 pm
= p
> view
->first
? p
+ 1 : view
->first
;
1222 if (!view
->wrap_mode
){
1227 line
+= move_forward2 (view
, pm
, 0, q
);
1232 return move_forward2 (view
, pm
, line
- lines
, 0);
1238 return p
> view
->first
? p
: view
->first
;
1242 view_move_backward (WView
*view
, int i
)
1244 view
->search_start
= view
->start_display
=
1245 move_backward2 (view
, view
->start_display
, i
);
1246 view
->found_len
= 0;
1247 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1252 get_bottom_first (WView
*view
, int do_not_cache
, int really
)
1256 if (!have_fast_cpu
&& !really
)
1259 if (!do_not_cache
&& view
->bottom_first
!= -1)
1260 return view
->bottom_first
;
1263 if (view
->growing_buffer
){
1267 while (old_last_byte
!= view
->last_byte
){
1268 old_last_byte
= view
->last_byte
;
1269 get_byte (view
, view
->last_byte
+VIEW_PAGE_SIZE
);
1273 bottom_first
= move_backward2 (view
, view
->last_byte
, vheight
- 1);
1276 bottom_first
= (bottom_first
+ view
->bytes_per_line
- 1)
1277 / view
->bytes_per_line
* view
->bytes_per_line
;
1278 view
->bottom_first
= bottom_first
;
1280 return view
->bottom_first
;
1284 view_move_forward (WView
*view
, int i
)
1286 view
->start_display
= move_forward2 (view
, view
->start_display
, i
, 0);
1287 if (!view
->reading_pipe
&& view
->start_display
> get_bottom_first (view
, 0, 0))
1288 view
->start_display
= view
->bottom_first
;
1289 view
->search_start
= view
->start_display
;
1290 view
->found_len
= 0;
1291 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1297 move_to_top (WView
*view
)
1299 view
->search_start
= view
->start_display
= view
->first
;
1300 view
->found_len
= 0;
1301 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1302 view
->nib_shift
= 0;
1303 view
->edit_cursor
= view
->start_display
;
1308 move_to_bottom (WView
*view
)
1310 view
->search_start
= view
->start_display
= get_bottom_first (view
, 0, 1);
1311 view
->found_len
= 0;
1312 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1313 view
->edit_cursor
= (view
->edit_cursor
< view
->start_display
) ?
1314 view
->start_display
: view
->edit_cursor
;
1318 /* Scroll left/right the view panel functions */
1320 move_right (WView
*view
)
1322 if (view
->wrap_mode
&& !view
->hex_mode
)
1324 if (view
->hex_mode
) {
1325 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1327 if (view
->hex_mode
&& view
->view_side
== view_side_left
) {
1328 view
->nib_shift
= 1 - view
->nib_shift
;
1329 if (view
->nib_shift
== 1)
1332 view
->edit_cursor
= (++view
->edit_cursor
< view
->last_byte
) ?
1333 view
->edit_cursor
: view
->last_byte
- 1;
1334 if (view
->edit_cursor
>= view
->last
) {
1335 view
->edit_cursor
-= view
->bytes_per_line
;
1336 view_move_forward(view
, 1);
1339 if (--view
->start_col
> 0)
1340 view
->start_col
= 0;
1345 move_left (WView
*view
)
1347 if (view
->wrap_mode
&& !view
->hex_mode
)
1349 if (view
->hex_mode
) {
1350 if (view
->hex_mode
&& view
->view_side
== view_side_left
) {
1351 view
->nib_shift
= 1 - view
->nib_shift
;
1352 if (view
->nib_shift
== 0)
1355 if (view
->edit_cursor
> view
->first
)
1356 --view
->edit_cursor
;
1357 if (view
->edit_cursor
< view
->start_display
) {
1358 view
->edit_cursor
+= view
->bytes_per_line
;
1359 view_move_backward(view
, 1);
1362 if (++view
->start_col
> 0)
1363 view
->start_col
= 0;
1368 /* {{{ Search routines */
1370 /* Case insensitive search of text in data */
1372 icase_search_p (WView
*view
, char *text
, char *data
, int nothing
)
1377 if ((q
= _icase_search (text
, data
, &lng
)) != 0) {
1378 view
->found_len
= lng
;
1379 view
->search_start
= q
- data
- lng
;
1386 grow_string_buffer (char *text
, int *size
)
1390 /* The grow steps */
1392 new = g_realloc (text
, *size
);
1400 get_line_at (WView
*view
, unsigned long *p
, unsigned long *skipped
)
1403 int buffer_size
= 0;
1404 int usable_size
= 0;
1406 int direction
= view
->direction
;
1407 unsigned long pos
= *p
;
1411 /* skip over all the possible zeros in the file */
1412 while ((ch
= get_byte (view
, pos
)) == 0) {
1413 pos
+= direction
; i
++;
1418 prev
= get_byte (view
, pos
- 1);
1419 if ((prev
== -1) || (prev
== '\n'))
1423 for (i
= 0; ch
!= -1; ch
= get_byte (view
, pos
)){
1425 if (i
== usable_size
){
1426 buffer
= grow_string_buffer (buffer
, &buffer_size
);
1427 usable_size
= buffer_size
- 2;
1430 pos
+= direction
; i
++;
1432 if (ch
== '\n' || !ch
){
1441 /* If we are searching backwards, reverse the string */
1442 if (direction
< 0) {
1443 reverse_string (buffer
+ 1);
1451 /** Search status optmizations **/
1453 /* The number of bytes between percent increments */
1454 static int update_steps
;
1456 /* Last point where we updated the status */
1457 static long update_activate
;
1460 search_update_steps (WView
*view
)
1462 if (view
->s
.st_size
)
1463 update_steps
= 40000;
1465 update_steps
= view
->last_byte
/ 100;
1467 /* Do not update the percent display but every 20 ks */
1468 if (update_steps
< 20000)
1469 update_steps
= 20000;
1473 search (WView
*view
, char *text
, int (*search
)(WView
*, char *, char *, int))
1475 int w
= view
->widget
.cols
- view
->have_frame
+ 1;
1477 char *s
= NULL
; /* The line we read from the view buffer */
1479 int found_len
, search_start
;
1483 /* Used to keep track of where the line starts, when looking forward */
1484 /* is the index before transfering the line; the reverse case uses */
1485 /* the position returned after the line has been read */
1486 long forward_line_start
;
1487 long reverse_line_start
;
1489 /* Clear interrupt status */
1493 d
= message (D_INSERT
, _(" Search "), _("Searching %s"), text
);
1497 found_len
= view
->found_len
;
1498 search_start
= view
->search_start
;
1500 if (view
->direction
== 1){
1501 p
= found_len
? search_start
+ 1 : search_start
;
1503 p
= (found_len
? search_start
: view
->last
) - 1;
1507 /* Compute the percent steps */
1508 search_update_steps (view
);
1509 update_activate
= 0;
1511 for (; ; g_free (s
)){
1512 if (p
>= update_activate
){
1513 update_activate
+= update_steps
;
1515 view_percent (view
, p
, w
, TRUE
);
1518 if (got_interrupt ())
1521 forward_line_start
= p
;
1522 disable_interrupt_key ();
1523 s
= get_line_at (view
, &p
, &t
);
1524 reverse_line_start
= p
;
1525 enable_interrupt_key ();
1530 search_status
= (*search
) (view
, text
, s
+ 1, match_normal
);
1531 if (search_status
< 0){
1536 if (search_status
== 0)
1539 /* We found the string */
1541 if (*s
&& !view
->search_start
&& (search
== regexp_view_search
) && (*text
== '^')){
1543 /* We do not want to match a
1544 * ^ regexp when not at the real
1545 * beginning of some line
1549 /* Record the position used to continue the search */
1550 if (view
->direction
== 1)
1551 t
+= forward_line_start
;
1553 t
+= reverse_line_start
? reverse_line_start
+ 3 : 0;
1554 view
->search_start
+= t
;
1556 if (t
!= beginning
){
1557 if (t
> get_bottom_first (view
, 0, 0))
1558 view
->start_display
= view
->bottom_first
;
1560 view
->start_display
= t
;
1566 disable_interrupt_key ();
1572 message (0, _(" Search "), _(" Search string not found "));
1573 view
->found_len
= 0;
1577 /* Search buffer (it's size is len) in the complete buffer */
1578 /* returns the position where the block was found or -1 if not found */
1580 block_search (WView
*view
, char *buffer
, int len
)
1582 int w
= view
->widget
.cols
- view
->have_frame
+ 1;
1584 char *d
= buffer
, b
;
1587 /* clear interrupt status */
1589 enable_interrupt_key ();
1590 e
= view
->found_len
? view
->search_start
+ 1 : view
->search_start
;
1592 search_update_steps (view
);
1593 update_activate
= 0;
1595 while (e
< view
->last_byte
){
1596 if (e
>= update_activate
){
1597 update_activate
+= update_steps
;
1599 view_percent (view
, e
, w
, TRUE
);
1602 if (got_interrupt ())
1605 b
= get_byte (view
, e
++);
1609 if (d
- buffer
== len
){
1610 disable_interrupt_key ();
1618 disable_interrupt_key ();
1623 * Search in the hex mode. Supported input:
1624 * - numbers (oct, dec, hex). Each of them matches one byte.
1625 * - strings in double quotes. Matches exactly without quotes.
1628 hex_search (WView
*view
, char *text
)
1630 char *buffer
; /* Parsed search string */
1631 char *cur
; /* Current position in it */
1632 int block_len
; /* Length of the search string */
1633 long pos
; /* Position of the string in the file */
1634 int parse_error
= 0;
1637 view
->found_len
= 0;
1641 /* buffer will never be longer that text */
1642 buffer
= g_new (char, strlen (text
));
1645 /* First convert the string to a stream of bytes */
1650 /* Skip leading spaces */
1651 if (*text
== ' ' || *text
== '\t') {
1656 /* %i matches octal, decimal, and hexadecimal numbers */
1657 if (sscanf (text
, "%i%n", &val
, &ptr
) > 0) {
1658 /* Allow signed and unsigned char in the user input */
1659 if (val
< -128 || val
> 255) {
1664 *cur
++ = (char) val
;
1669 /* Try quoted string, strip quotes */
1674 next_quote
= strchr (text
, '"');
1676 memcpy (cur
, text
, next_quote
- text
);
1677 cur
+= next_quote
- text
;
1678 text
= next_quote
+ 1;
1688 block_len
= cur
- buffer
;
1690 /* No valid bytes in the user input */
1691 if (block_len
<= 0 || parse_error
) {
1692 message (0, _(" Search "), _("Invalid hex search expression"));
1694 view
->found_len
= 0;
1698 /* Then start the search */
1699 pos
= block_search (view
, buffer
, block_len
);
1704 message (0, _(" Search "), _(" Search string not found "));
1705 view
->found_len
= 0;
1709 view
->search_start
= pos
;
1710 view
->found_len
= block_len
;
1711 /* Set the edit cursor to the search position, left nibble */
1712 view
->edit_cursor
= view
->search_start
;
1713 view
->nib_shift
= 0;
1715 /* Adjust the file offset */
1716 view
->start_display
= (pos
& (~(view
->bytes_per_line
-1)));
1717 if (view
->start_display
> get_bottom_first (view
, 0, 0))
1718 view
->start_display
= view
->bottom_first
;
1721 static int regexp_view_search (WView
*view
, char *pattern
, char *string
, int match_type
)
1724 static char *old_pattern
= NULL
;
1725 static int old_type
;
1726 regmatch_t pmatch
[1];
1727 int i
, flags
= REG_ICASE
;
1729 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
){
1732 g_free (old_pattern
);
1735 for (i
= 0; pattern
[i
] != 0; i
++){
1736 if (isupper ((unsigned char) pattern
[i
])){
1741 flags
|= REG_EXTENDED
;
1742 if (regcomp (&r
, pattern
, flags
)){
1743 message (1, MSG_ERROR
, _(" Invalid regular expression "));
1746 old_pattern
= g_strdup (pattern
);
1747 old_type
= match_type
;
1749 if (regexec (&r
, string
, 1, pmatch
, 0) != 0)
1751 view
->found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1752 view
->search_start
= pmatch
[0].rm_so
;
1756 static void do_regexp_search (void *xview
, char *regexp
)
1758 WView
*view
= (WView
*) xview
;
1760 view
->search_exp
= regexp
;
1761 search (view
, regexp
, regexp_view_search
);
1762 /* Had a refresh here */
1764 view_update (view
, TRUE
);
1767 static void do_normal_search (void *xview
, char *text
)
1769 WView
*view
= (WView
*) xview
;
1771 view
->search_exp
= text
;
1773 hex_search (view
, text
);
1775 search (view
, text
, icase_search_p
);
1776 /* Had a refresh here */
1778 view_update (view
, TRUE
);
1782 /* {{{ Mouse and keyboard handling */
1784 /* Real view only */
1785 static void view_help_cmd (void)
1787 interactive_display (NULL
, "[Internal File Viewer]");
1794 static void toggle_wrap_mode (WView
*view
)
1796 if (view
->hex_mode
) {
1797 if (view
->growing_buffer
!= 0) {
1800 get_bottom_first (view
, 1, 1);
1801 if (view
->hexedit_mode
) {
1802 view
->view_side
= 1 - view
->view_side
;
1804 view
->hexedit_mode
= 1 - view
->hexedit_mode
;
1808 view_update (view
, TRUE
);
1811 view
->wrap_mode
= 1 - view
->wrap_mode
;
1812 get_bottom_first (view
, 1, 1);
1813 if (view
->wrap_mode
)
1814 view
->start_col
= 0;
1817 if (view
->bottom_first
< view
->start_display
)
1818 view
->search_start
= view
->start_display
= view
->bottom_first
;
1819 view
->found_len
= 0;
1824 view_update (view
, TRUE
);
1829 toggle_hex_mode (WView
*view
)
1831 view
->hex_mode
= 1 - view
->hex_mode
;
1833 if (view
->hex_mode
){
1834 /* Shift the line start to 0x____0 on entry, restore it for Ascii */
1835 view
->start_save
= view
->start_display
;
1836 view
->start_display
-= view
->start_display
% view
->bytes_per_line
;
1837 view
->edit_cursor
= view
->start_display
;
1838 view
->widget
.options
|= W_WANT_CURSOR
;
1839 view
->widget
.parent
->flags
|= DLG_WANT_TAB
;
1841 view
->start_display
= view
->start_save
;
1842 view
->widget
.parent
->flags
&= ~DLG_WANT_TAB
;
1843 view
->widget
.options
&= ~W_WANT_CURSOR
;
1845 altered_hex_mode
= 1;
1846 get_bottom_first (view
, 1, 1);
1849 view_update (view
, TRUE
);
1854 goto_line (WView
*view
)
1856 char *line
, prompt
[BUF_SMALL
];
1858 int saved_wrap_mode
= view
->wrap_mode
;
1861 view
->wrap_mode
= 0;
1862 for (i
= view
->first
; i
< view
->start_display
; i
++)
1863 if (get_byte (view
, i
) == '\n')
1865 g_snprintf (prompt
, sizeof (prompt
), _(" The current line number is %d.\n"
1866 " Enter the new line number:"), oldline
);
1867 line
= input_dialog (_(" Goto line "), prompt
, "");
1871 view_move_forward (view
, atol (line
) - 1);
1876 view
->wrap_mode
= saved_wrap_mode
;
1877 view_update (view
, TRUE
);
1882 goto_addr (WView
*view
)
1884 char *line
, *error
, prompt
[BUF_SMALL
];
1887 g_snprintf (prompt
, sizeof (prompt
), _(" The current address is 0x%lx.\n"
1888 " Enter the new address:"), view
->edit_cursor
);
1889 line
= input_dialog (_(" Goto Address "), prompt
, "");
1892 addr
= strtol (line
, &error
, 0);
1893 if ((*error
== '\0') && (addr
<= view
->last_byte
)) {
1895 view_move_forward (view
, addr
/view
->bytes_per_line
);
1896 view
->edit_cursor
= addr
;
1902 view_update (view
, TRUE
);
1907 regexp_search (WView
*view
, int direction
)
1910 static char *old
= 0;
1912 /* This is really an F6 key handler */
1913 if (view
->hex_mode
){
1914 /* Save it without a confirmation prompt */
1915 if (view
->change_list
)
1916 save_edit_changes(view
);
1920 regexp
= old
? old
: regexp
;
1921 regexp
= input_dialog (_(" Search "), _(" Enter regexp:"), regexp
);
1933 /* Mhm, do we really need to load all the file in the core? */
1934 if (view
->bytes_read
< view
->last_byte
)
1935 get_byte (view
, view
->last_byte
-1);/* Get the whole file in to memory */
1937 view
->direction
= direction
;
1938 do_regexp_search (view
, regexp
);
1940 view
->last_search
= do_regexp_search
;
1944 regexp_search_cmd (WView
*view
)
1946 regexp_search (view
, 1);
1951 normal_search (WView
*view
, int direction
)
1956 exp
= old
? old
: exp
;
1960 convert_to_display( exp
);
1963 exp
= input_dialog (_(" Search "), _(" Enter search string:"), exp
);
1976 convert_from_input( exp
);
1979 view
->direction
= direction
;
1980 do_normal_search (view
, exp
);
1981 view
->last_search
= do_normal_search
;
1985 normal_search_cmd (WView
*view
)
1987 normal_search (view
, 1);
1991 change_viewer (WView
*view
)
1997 if (*view
->filename
) {
1998 altered_magic_flag
= 1;
1999 view
->viewer_magic_flag
= !view
->viewer_magic_flag
;
2000 s
= g_strdup (view
->filename
);
2002 t
= g_strdup (view
->command
);
2007 view_init (view
, t
, s
, 0);
2013 view_update (view
, TRUE
);
2018 change_nroff (WView
*view
)
2020 view
->viewer_nroff_flag
= !view
->viewer_nroff_flag
;
2021 altered_nroff_flag
= 1;
2024 view_update (view
, TRUE
);
2027 /* Real view only */
2029 view_quit_cmd (WView
*view
)
2031 if (view_ok_to_quit (view
))
2032 dlg_stop (view
->widget
.parent
);
2037 view_labels (WView
*view
)
2039 Dlg_head
*h
= view
->widget
.parent
;
2041 define_label (h
, (Widget
*) view
, 1, _("Help"), view_help_cmd
);
2043 my_define (h
, 10, _("Quit"), view_quit_cmd
, view
);
2044 my_define (h
, 4, view
->hex_mode
? _("Ascii"): _("Hex"), toggle_hex_mode
, view
);
2045 my_define (h
, 5, view
->hex_mode
? _("Goto") : _("Line"),
2046 view
->hex_mode
? goto_addr
: goto_line
,
2048 my_define (h
, 6, view
->hex_mode
? _("Save") : _("RxSrch"), regexp_search_cmd
, view
);
2050 my_define (h
, 2, view
->hex_mode
? view
->hexedit_mode
?
2051 view
->view_side
== view_side_left
? _("EdText") : _("EdHex") :
2052 view
->growing_buffer
? "" : _("Edit") :
2053 view
->wrap_mode
? _("UnWrap") : _("Wrap"),
2054 toggle_wrap_mode
, view
);
2056 my_define (h
, 7, view
->hex_mode
? _("HxSrch") : _("Search"),
2057 normal_search_cmd
, view
);
2059 my_define (h
, 8, view
->viewer_magic_flag
? _("Raw") : _("Parse"),
2060 change_viewer
, view
);
2062 if (!view
->have_frame
){
2063 my_define (h
, 9, view
->viewer_nroff_flag
? _("Unform") : _("Format"),
2064 change_nroff
, view
);
2065 my_define (h
, 3, _("Quit"), view_quit_cmd
, view
);
2068 redraw_labels (h
, (Widget
*) view
);
2073 check_left_right_keys (WView
*view
, int c
)
2077 else if (c
== KEY_RIGHT
)
2085 set_monitor (WView
*view
, int set_on
)
2087 int old
= view
->monitor
;
2089 view
->monitor
= set_on
;
2092 move_to_bottom (view
);
2093 view
->bottom_first
= -1;
2094 set_idle_proc (view
->widget
.parent
, 1);
2097 set_idle_proc (view
->widget
.parent
, 0);
2102 continue_search (WView
*view
)
2104 if (view
->last_search
){
2105 (*view
->last_search
)(view
, view
->search_exp
);
2107 /* if not... then ask for an expression */
2108 normal_search (view
, 1);
2114 view_handle_key (WView
*view
, int c
)
2116 int prev_monitor
= view
->monitor
;
2118 set_monitor (view
, off
);
2121 if (c
>= 128 && c
<= 255) {
2122 c
= conv_input
[ c
];
2126 if (view
->hex_mode
) {
2128 case 0x09: /* Tab key */
2129 view
->view_side
= 1 - view
->view_side
;
2133 case XCTRL('a'): /* Beginning of line */
2134 view
->edit_cursor
-= view
->edit_cursor
% view
->bytes_per_line
;
2138 case XCTRL('b'): /* Character back */
2142 case XCTRL('e'): /* End of line */
2143 view
->edit_cursor
-= view
->edit_cursor
% view
->bytes_per_line
;
2144 view
->edit_cursor
+= view
->bytes_per_line
- 1;
2148 case XCTRL('f'): /* Character forward */
2153 /* Trap 0-9,A-F,a-f for left side data entry (hex editing) */
2154 if (view
->view_side
== view_side_left
){
2155 if ((c
>= '0' && c
<= '9') ||
2156 (c
>= 'A' && c
<= 'F') ||
2157 (c
>= 'a' && c
<= 'f')){
2159 put_editkey (view
, c
);
2164 /* Trap all printable characters for right side data entry */
2165 /* Also enter the value of the Enter key */
2166 if (view
->view_side
== view_side_right
){
2167 if (c
< 256 && (is_printable (c
) || (c
== '\n'))){
2168 put_editkey(view
, c
);
2174 if (check_left_right_keys (view
, c
))
2177 if (check_movement_keys (c
, 1, vheight
, view
, (movefn
) view_move_backward
, (movefn
) view_move_forward
,
2178 (movefn
) move_to_top
, (movefn
) move_to_bottom
)){
2184 regexp_search (view
, -1);
2188 regexp_search (view
, 1);
2191 /* Continue search */
2195 continue_search (view
);
2199 if (view
->last_search
){
2200 (*view
->last_search
)(view
, view
->search_exp
);
2202 normal_search (view
, -1);
2226 view_move_forward (view
, 1);
2230 view_move_forward (view
, vheight
/ 2);
2234 view_move_backward (view
, vheight
/ 2);
2239 view_move_backward (view
, 1);
2248 view_move_forward (view
, vheight
- 1);
2255 /* Unlike Ctrl-O, run a new shell if the subshell is not running. */
2261 set_monitor (view
, on
);
2265 view_move_backward (view
, vheight
- 1);
2269 view_move_backward (view
, 2);
2273 view_move_forward (view
, 2);
2277 view
->marks
[view
->marker
] = view
->start_display
;
2281 view
->start_display
= view
->marks
[view
->marker
];
2285 /* Use to indicate parent that we want to see the next/previous file */
2286 /* Only works on full screen mode */
2289 if (!view
->have_frame
)
2290 view
->move_dir
= c
== XCTRL('f') ? 1 : -1;
2296 if (view_ok_to_quit (view
))
2297 view
->view_quit
= 1;
2302 do_select_codepage();
2304 view_update( view
, TRUE
);
2306 #endif /* HAVE_CHARSET */
2309 if (c
>= '0' && c
<= '9')
2310 view
->marker
= c
- '0';
2312 /* Restore the monitor status */
2313 set_monitor (view
, prev_monitor
);
2321 view_event (WView
*view
, Gpm_Event
*event
, int *result
)
2323 *result
= MOU_NORMAL
;
2324 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2325 if (!view
->wrap_mode
){
2326 if (event
->x
< view
->widget
.cols
/ 4){
2328 *result
= MOU_REPEAT
;
2331 if (event
->x
> 3 * vwidth
/ 4){
2333 *result
= MOU_REPEAT
;
2337 if (event
->y
< view
->widget
.lines
/ 3){
2338 if (mouse_move_pages_viewer
)
2339 view_move_backward (view
, view
->widget
.lines
/ 2 - 1);
2341 view_move_backward (view
, 1);
2342 *result
= MOU_REPEAT
;
2345 else if (event
->y
> 2 * vheight
/3){
2346 if (mouse_move_pages_viewer
)
2347 view_move_forward (view
, vheight
/ 2 - 1);
2349 view_move_forward (view
, 1);
2350 *result
= MOU_REPEAT
;
2357 /* Real view only */
2359 real_view_event (Gpm_Event
*event
, void *x
)
2363 if (view_event ((WView
*) x
, event
, &result
))
2364 view_update ((WView
*) x
, TRUE
);
2369 /* {{{ Window creation, destruction and a driver stub for real view */
2372 view_adjust_size (Dlg_head
*h
)
2377 /* Look up the viewer and the buttonbar, we assume only two widgets here */
2378 view
= (WView
*) find_widget_type (h
, (callback_fn
) view_callback
);
2379 bar
= (WButtonBar
*) view
->widget
.parent
->current
->next
->widget
;
2380 widget_set_size (&view
->widget
, 0, 0, LINES
-1, COLS
);
2381 widget_set_size (&bar
->widget
, LINES
-1, 0, 1, COLS
);
2383 view_update_bytes_per_line(view
);
2386 /* Only the text mode edition uses this */
2389 /* Real view only */
2391 view (char *_command
, const char *_file
, int *move_dir_p
, int start_line
)
2398 /* Create dialog and widgets, put them on the dialog */
2400 create_dlg (0, 0, LINES
, COLS
, NULL
, NULL
,
2401 "[Internal File Viewer]", NULL
, DLG_NONE
);
2404 wview
= view_new (0, 0, COLS
, LINES
- 1, 0);
2406 bar
= buttonbar_new (1);
2408 add_widget (our_dlg
, wview
);
2409 add_widget (our_dlg
, bar
);
2411 error
= view_init (wview
, _command
, _file
, start_line
);
2415 /* Please note that if you add another widget,
2416 * you have to modify view_adjust_size to
2422 *move_dir_p
= wview
->move_dir
;
2424 destroy_dlg (our_dlg
);
2432 WView
*view
= (WView
*) v
;
2435 /* If the user is busy typing, wait until he finishes to update the
2438 if (!hook_present (idle_hook
, view_hook
))
2439 add_hook (&idle_hook
, view_hook
, v
);
2443 delete_hook (&idle_hook
, view_hook
);
2445 if (get_current_type () == view_listing
)
2447 else if (get_other_type () == view_listing
)
2448 panel
= other_panel
;
2452 view_init (view
, 0, panel
->dir
.list
[panel
->selected
].fname
, 0);
2454 view_status (view
, TRUE
);
2458 view_callback (Dlg_head
*h
, WView
*view
, int msg
, int par
)
2464 if (view
->have_frame
)
2465 add_hook (&select_file_hook
, view_hook
, view
);
2472 view_status (view
, TRUE
);
2477 view_place_cursor (view
);
2481 i
= view_handle_key ((WView
*)view
, par
);
2482 if (view
->view_quit
)
2485 view_update (view
, TRUE
);
2490 /* This event is generated when the user is using the 'F' flag */
2491 view
->bottom_first
= -1;
2492 move_to_bottom (view
);
2494 view_status (view
, TRUE
);
2503 return default_proc (h
, msg
, par
);
2507 view_new (int y
, int x
, int cols
, int lines
, int is_panel
)
2509 WView
*view
= g_new0 (WView
, 1);
2511 init_widget (&view
->widget
, y
, x
, lines
, cols
,
2512 (callback_fn
) view_callback
,
2513 (destroy_fn
) view_destroy
,
2514 (mouse_h
) real_view_event
, NULL
);
2516 view
->hex_mode
= default_hex_mode
;
2517 view
->hexedit_mode
= default_hexedit_mode
;
2518 view
->viewer_magic_flag
= default_magic_flag
;
2519 view
->viewer_nroff_flag
= default_nroff_flag
;
2520 view
->have_frame
= is_panel
;
2521 view
->last_byte
= -1;
2522 view
->wrap_mode
= global_wrap_mode
;
2524 widget_want_cursor (view
->widget
, 0);
2530 /* {{{ Emacs local variables */
2532 Cause emacs to enter folding mode for this file: