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
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 /* {{{ Declarations */
33 #include <sys/types.h>
41 # include <sys/mman.h>
47 #include <ctype.h> /* For toupper() */
48 #include <stdlib.h> /* atoi() */
52 #include <sys/param.h>
56 #include "dlg.h" /* Needed by widget.h */
57 #include "widget.h" /* Needed for buttonbar_new */
64 #include "key.h" /* For mi_getch() */
66 #include "wtools.h" /* For query_set_sel() */
67 #if defined(HAVE_RX_H) && defined(HAVE_REGCOMP)
73 #include "../vfs/vfs.h"
75 #include "panel.h" /* Needed for current_panel and other_panel */
77 #include "main.h" /* For the externs */
85 /* Block size for reading files in parts */
86 #define READ_BLOCK 8192
87 #define VIEW_PAGE_SIZE 8192
90 # define IFAIX(x) case (x):
95 /* Maxlimit for skipping updates */
104 static int view_callback (Dlg_head
*h
, WView
*view
, int msg
, int par
);
106 /* If set, show a ruler */
109 /* Scrolling is done in pages or line increments */
110 int mouse_move_pages_viewer
= 1;
112 /* Used to compute the bottom first variable */
113 int have_fast_cpu
= 0;
115 /* wrap mode default */
116 int global_wrap_mode
= 1;
118 int default_hex_mode
= 0;
119 int default_hexedit_mode
= 0;
120 int default_magic_flag
= 1;
121 int default_nroff_flag
= 1;
122 int altered_hex_mode
= 0;
123 int altered_magic_flag
= 0;
124 int altered_nroff_flag
= 0;
129 static char hex_char
[] = "0123456789ABCDEF";
132 /* {{{ Clean-up functions */
135 close_view_file (WView
*view
)
137 if (view
->file
!= -1){
138 mc_close (view
->file
);
144 free_file (WView
*view
)
151 mc_munmap (view
->data
, view
->s
.st_size
);
152 close_view_file (view
);
154 #endif /* HAVE_MMAP */
156 if (view
->reading_pipe
){
157 /* Check error messages */
158 if (!view
->have_frame
)
162 pclose (view
->stdfile
);
163 view
->stdfile
= NULL
;
165 /* Ignore errors because we don't want to hear about broken pipe */
166 close_error_pipe (-1, NULL
);
168 close_view_file (view
);
170 /* Block_ptr may be zero if the file was a file with 0 bytes */
171 if (view
->growing_buffer
&& view
->block_ptr
){
172 for (i
= 0; i
< view
->blocks
; i
++){
173 free (view
->block_ptr
[i
].data
);
175 free (view
->block_ptr
);
179 /* Valid parameters for second parameter to set_monitor */
184 view_done (WView
*view
)
186 set_monitor (view
, off
);
188 /* alex: release core, used to replace mmap */
189 if (!view
->growing_buffer
&& view
->data
!= (unsigned char*)0)
194 #endif /* HAVE_MMAP */
196 if (view
->view_active
){
198 mc_ungetlocalcopy (view
->filename
, view
->localcopy
, 0);
200 free (view
->filename
);
202 free (view
->command
);
204 view
->view_active
= 0;
205 default_hex_mode
= view
->hex_mode
;
206 default_nroff_flag
= view
->viewer_nroff_flag
;
207 default_magic_flag
= view
->viewer_magic_flag
;
210 static void view_hook (void *);
213 view_destroy (WView
*view
)
216 if (view
->have_frame
)
217 delete_hook (&select_file_hook
, view_hook
);
218 x_destroy_view (view
);
222 get_byte (WView
*view
, int byte_index
)
224 int page
= byte_index
/ VIEW_PAGE_SIZE
+ 1;
225 int offset
= byte_index
% VIEW_PAGE_SIZE
;
229 if (view
->growing_buffer
){
230 if (page
> view
->blocks
){
231 tmp
= xmalloc (sizeof (block_ptr_t
) * page
, "get_byte");
232 if (view
->block_ptr
){
233 bcopy (view
->block_ptr
, tmp
, sizeof (block_ptr_t
) *
235 free (view
->block_ptr
);
237 view
->block_ptr
= tmp
;
238 for (i
= view
->blocks
; i
< page
; i
++){
239 char *p
= malloc (VIEW_PAGE_SIZE
);
240 view
->block_ptr
[i
].data
= p
;
243 if (view
->stdfile
!= NULL
)
244 n
= fread (p
, 1, VIEW_PAGE_SIZE
, view
->stdfile
);
246 n
= mc_read (view
->file
, p
, VIEW_PAGE_SIZE
);
248 view
->bytes_read
+= n
;
249 if (view
->s
.st_size
< view
->bytes_read
){
250 view
->bottom_first
= -1; /* Invalidate cache */
251 view
->s
.st_size
= view
->bytes_read
;
252 view
->last_byte
= view
->bytes_read
;
253 if (view
->reading_pipe
)
254 view
->last_byte
= view
->first
+ view
->bytes_read
;
256 /* To force loading the next page */
257 if (n
== VIEW_PAGE_SIZE
&& view
->reading_pipe
){
263 if (byte_index
> view
->bytes_read
){
266 return view
->block_ptr
[page
-1].data
[offset
];
268 if (byte_index
>= view
->last_byte
)
271 return view
->data
[byte_index
];
276 enqueue_change (struct hexedit_change_node
**head
, struct hexedit_change_node
*node
)
278 struct hexedit_change_node
*curr
= *head
;
281 if (node
->offset
< curr
->offset
) {
286 head
= (struct hexedit_change_node
**) curr
;
293 static void move_right (WView
*);
296 put_editkey (WView
*view
, unsigned char key
)
298 struct hexedit_change_node
*node
;
299 unsigned char byte_val
;
301 if (!view
->hexedit_mode
|| view
->growing_buffer
!= 0)
304 /* Has there been a change at this position ? */
305 node
= view
->change_list
;
307 if (node
->offset
!= view
->edit_cursor
)
313 if (view
->view_side
== view_side_left
) {
316 if (key
>= '0' && key
<= '9')
318 else if (key
>= 'A' && key
<= 'F')
320 else if (key
>= 'a' && key
<= 'f')
326 byte_val
= node
->value
;
328 byte_val
= get_byte(view
, view
->edit_cursor
);
330 if (view
->nib_shift
== 0) {
331 byte_val
= (byte_val
& 0x0f) | (key
<< 4);
333 byte_val
= (byte_val
& 0xf0) | (key
);
340 node
= (struct hexedit_change_node
*)
341 xmalloc(sizeof(struct hexedit_change_node
), "HexEdit");
346 ** alex@bcs.zaporizhzhe.ua: here we are using file copy
347 ** completely loaded into memory, so we can replace bytes
348 ** in view->data array to allow changes to be reflected
349 ** when user switches back to ascii mode
351 view
->data
[view
->edit_cursor
] = byte_val
;
352 #endif /* HAVE_MMAP */
353 node
->offset
= view
->edit_cursor
;
354 node
->value
= byte_val
;
355 enqueue_change (&view
->change_list
, node
);
358 node
->value
= byte_val
;
366 free_change_list (WView
*view
)
368 struct hexedit_change_node
*n
= view
->change_list
;
371 view
->change_list
= n
->next
;
373 n
= view
->change_list
;
375 view
->file_dirty
= 0;
380 save_edit_changes (WView
*view
)
382 struct hexedit_change_node
*node
= view
->change_list
;
385 fp
= open (view
->filename
, O_WRONLY
);
388 lseek (fp
, node
->offset
, SEEK_SET
);
389 write (fp
, &node
->value
, 1);
394 free_change_list (view
);
398 view_ok_to_quit (WView
*view
)
403 if (!view
->change_list
)
407 text
= copy_strings (_("File: \n\n "), view
->filename
,
408 _("\n\nhas been modified, do you want to save the changes?\n"), NULL
);
410 r
= query_dialog (_(" Save changes "), text
, 2, 3, _("&Yes"), _("&No"), _("&Cancel"));
415 save_edit_changes (view
);
418 free_change_list (view
);
426 set_view_init_error (WView
*view
, char *msg
)
428 view
->growing_buffer
= 0;
429 view
->reading_pipe
= 0;
433 view
->bytes_read
= strlen (msg
);
439 /* return values: 0 for success, else points to error message */
441 init_growing_view (WView
*view
, char *name
, char *filename
)
443 view
->growing_buffer
= 1;
446 view
->reading_pipe
= 1;
450 if ((view
->stdfile
= popen (name
, "r")) == NULL
){
451 close_error_pipe (view
->have_frame
?-1:1, view
->data
);
452 return set_view_init_error (view
, _(" Can't spawn child program "));
456 /* First, check if filter produced any output */
458 if (view
->bytes_read
<= 0){
459 pclose (view
->stdfile
);
460 view
->stdfile
= NULL
;
461 close_error_pipe (view
->have_frame
?-1:1, view
->data
);
462 return set_view_init_error (view
, _(" Empty output from child filter "));
466 view
->stdfile
= NULL
;
467 if ((view
->file
= mc_open (filename
, O_RDONLY
)) == -1)
468 return set_view_init_error (view
, _(" Could not open file "));
473 /* Load filename into core */
476 if (have_frame), we return success, but data points to a
477 error message instead of the file buffer (quick_view feature).
479 static char *load_view_file (WView
*view
, char *filename
)
484 if ((view
->file
= mc_open (filename
, O_RDONLY
)) < 0){
485 set_view_init_error (view
, 0);
486 return (copy_strings (_(" Can't open file \""),
488 unix_error_string (errno
), " ", 0));
491 if (mc_fstat (view
->file
, &view
->s
) < 0){
492 set_view_init_error (view
, 0);
493 close_view_file (view
);
494 return copy_strings (_(" Can't stat file \n "),
495 unix_error_string (errno
), " ", 0);
497 if (S_ISDIR (view
->s
.st_mode
) || S_ISSOCK (view
->s
.st_mode
)
498 || S_ISFIFO (view
->s
.st_mode
)){
499 close_view_file (view
);
500 return set_view_init_error (view
, _(" Can't view: not a regular file "));
503 if (view
->s
.st_size
== 0){
504 /* Must be one of those nice files that grow (/proc) */
505 close_view_file (view
);
506 return init_growing_view (view
, 0, filename
);
509 /* First, try to open a compressed file */
510 if (view
->viewer_magic_flag
&& (is_gunzipable (view
->file
, &type
)) != 0){
511 close_view_file (view
);
512 if (vfs_file_is_local (filename
)) {
513 char *tmp
= name_quote (filename
, 0);
514 cmd
= copy_strings (decompress_command (type
), " ", tmp
, 0);
519 if ((view
->localcopy
= mc_getlocalcopy (filename
)) == 0)
520 return set_view_init_error (view
, _(" Can not fetch local copy ") );
521 tmp
= name_quote (view
->localcopy
, 0);
522 cmd
= copy_strings (decompress_command (type
), " ", tmp
, 0);
525 return init_growing_view (view
, cmd
, filename
);
528 /* Otherwise, the file wasn't compressed */
530 view
->data
= mc_mmap (0, view
->s
.st_size
, PROT_READ
, MAP_FILE
| MAP_SHARED
,
532 if ((caddr_t
) view
->data
== (caddr_t
) -1){
533 close_view_file (view
);
534 /* set_view_init_error (view, 0);
535 return copy_strings (" Can't mmap file \n ",
536 unix_error_string (errno), " ", 0);*/
537 return init_growing_view (view
, 0, filename
);
542 view
->bytes_read
= view
->s
.st_size
;
545 #else /* ! HAVE_MMAP */
547 ** For those OS that dont provide mmap call. Try to load all the file
548 ** into memory (alex@bcs.zaporizhzhe.ua)
550 view
->data
= (unsigned char*) xmalloc (view
->s
.st_size
, "load_view_file");
551 if (view
->data
== (unsigned char*) 0
552 || mc_lseek(view
->file
,0,0) != 0
553 || mc_read(view
->file
, view
->data
, view
->s
.st_size
) != view
->s
.st_size
555 if (view
->data
!= (unsigned char*)0)
557 close_view_file (view
);
558 return init_growing_view (view
, 0, filename
);
561 view
->bytes_read
= view
->s
.st_size
;
566 /* Return zero on success, -1 on failure */
568 do_view_init (WView
*view
, char *_command
, char *_file
, int start_line
)
573 if (view
->view_active
)
576 /* Set up the state */
579 view
->growing_buffer
= 0;
580 view
->reading_pipe
= 0;
584 view
->first
= view
->bytes_read
= 0;
589 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
591 /* Clear the markers */
593 for (i
= 0; i
< 10; i
++)
597 if (!view
->have_frame
){
600 if (_command
&& (view
->viewer_magic_flag
|| _file
[0] == '\0'))
601 error
= init_growing_view (view
, _command
, _file
);
603 error
= load_view_file (view
, _file
);
606 if (!view
->have_frame
){
607 message (1, MSG_ERROR
, error
);
613 view
->view_active
= 1;
614 view
->filename
= strdup (_file
);
616 view
->command
= strdup (_command
);
619 view
->search_start
= view
->start_display
= view
->start_save
= view
->first
;
622 view
->last_search
= 0; /* Start a new search */
624 /* Special case: The data points to the error message */
627 view
->s
.st_size
= view
->bytes_read
= strlen (view
->data
);
629 view
->last_byte
= view
->first
+ view
->s
.st_size
;
631 if (start_line
> 1 && !error
){
632 int saved_wrap_mode
= view
->wrap_mode
;
636 view_move_forward (view
, start_line
- 1);
637 view
->wrap_mode
= saved_wrap_mode
;
639 view
->edit_cursor
= view
->first
;
640 view
->file_dirty
= 0;
642 view
->view_side
= view_side_left
;
643 view
->change_list
= NULL
;
650 /* Return zero on success, -1 on failure */
652 view_init (WView
*view
, char *_command
, char *_file
, int start_line
)
656 if (view
->have_frame
)
657 cols
= view
->widget
.cols
- 2;
659 cols
= view
->widget
.cols
;
661 view
->bottom_first
= -1;
662 view
->bytes_per_line
= 2 * (cols
- 7) / 9;
663 view
->bytes_per_line
&= 0xfffc;
664 view
->dirty
= max_dirt_limit
+ 1; /* To force refresh */
665 if (!view
->view_active
|| strcmp (_file
, view
->filename
) || altered_magic_flag
)
666 return do_view_init (view
, _command
, _file
, start_line
);
673 /* {{{ Screen update functions */
677 view_percent (WView
*view
, int p
, int w
)
681 percent
= (view
->s
.st_size
== 0 || view
->last_byte
== view
->last
) ? 100 :
683 p
/ (view
->s
.st_size
/ 100) :
684 p
* 100 / view
->s
.st_size
);
687 percent
= view
->s
.st_size
== 0 ? 100 :
688 (view
->last_byte
== view
->last
? 100 :
689 (p
)*100 / view
->s
.st_size
);
692 widget_move (view
, view
->have_frame
, w
- 5);
693 printw ("%3d%% ", percent
);
697 view_status (WView
*view
)
699 int w
= view
->widget
.cols
- (view
->have_frame
* 2);
702 attrset (SELECTED_COLOR
);
703 widget_move (view
, view
->have_frame
, view
->have_frame
);
706 i
= w
> 24 ? 18 : w
- 6;
707 printw (_("File: %s"), name_trunc (view
->filename
? view
->filename
:
708 view
->command
? view
->command
:"", i
));
710 widget_move (view
, view
->have_frame
, 24);
712 printw (_("Offset 0x%08x"), view
->edit_cursor
);
714 printw (_("Col %d"), -view
->start_col
);
717 widget_move (view
, view
->have_frame
, 42);
718 printw (_("%s bytes"), size_trunc (view
->s
.st_size
));
722 if (view
->growing_buffer
)
723 addstr (_(" [grow]"));
727 view_percent (view
, view
->edit_cursor
- view
->first
, w
);
729 view_percent (view
, view
->start_display
- view
->first
, w
);
731 attrset (SELECTED_COLOR
);
734 #define view_set_color(view,font) attrset (font)
737 view_display_clean (WView
*view
, int height
, int width
)
739 /* FIXME: Should I use widget_erase only and repaint the box? */
740 if (view
->have_frame
){
743 draw_double_box (view
->widget
.parent
, view
->widget
.y
, view
->widget
.x
,
744 view
->widget
.lines
, view
->widget
.cols
);
745 for (i
= 1; i
< height
; i
++){
746 widget_move (view
, i
, 1);
747 printw ("%*s", width
-1, "");
750 widget_erase ((Widget
*) view
);
753 #define view_add_character(view,c) addch (c)
754 #define view_add_string(view,s) addstr (s)
755 #define view_gotoyx(v,r,c) widget_move (v,r,c)
759 /* Both the text mode and gnome editions use this */
760 #define BOLD_COLOR MARKED_COLOR
761 #define UNDERLINE_COLOR VIEW_UNDERLINED_COLOR
762 #define MARK_COLOR SELECTED_COLOR
763 #define DEF_COLOR NORMAL_COLOR
766 #ifndef PORT_HAS_VIEW_FREEZE
767 # define view_freeze(view)
768 # define view_thaw(view)
772 # define PICK_COLOR(a,b) BOLD_COLOR : DEF_COLOR
774 # define PICK_COLOR(a,b) a : b
777 /* Shows the file pointed to by *start_display on view_win */
779 display (WView
*view
)
782 # define frame_shift 0
783 # define STATUS_LINES 0
785 const int frame_shift
= view
->have_frame
;
786 # define STATUS_LINES 1
788 int col
= 0 + frame_shift
;
789 int row
= STATUS_LINES
+ frame_shift
;
794 struct hexedit_change_node
*curr
= view
->change_list
;
796 height
= view
->widget
.lines
- frame_shift
;
797 width
= view
->widget
.cols
- frame_shift
;
798 from
= view
->start_display
;
799 view_set_color (view
, DEF_COLOR
);
802 view_display_clean (view
, height
, width
);
804 /* Optionally, display a ruler */
805 if ((!view
->hex_mode
) && (ruler
)){
809 view_set_color (view
, BOLD_COLOR
);
810 for (c
= frame_shift
; c
< width
; c
++) {
811 cl
= c
-view
->start_col
;
813 view_gotoyx (view
, row
, c
);
815 view_gotoyx (view
, row
+height
-2, c
);
822 view_add_character (view
, r_buff
[0]);
823 if ((cl
!= 0) && (cl
% 10) == 0){
824 sprintf(r_buff
, "%03d", cl
);
826 widget_move (view
, row
+ 1, c
- 1);
828 widget_move (view
, row
+ height
- 3, c
- 1);
829 view_add_string (view
, r_buff
);
832 view_set_color (view
, DEF_COLOR
);
839 /* Find the first displayable changed byte */
841 if (curr
->offset
< from
)
847 char hex_buff
[10]; /* A temporary buffer for sprintf and mvwaddstr */
848 int bytes
; /* Number of bytes already printed on the line */
850 /* Start of text column */
851 int text_start
= width
- view
->bytes_per_line
- 1 + frame_shift
;
853 for (;row
< height
&& from
< view
->last_byte
; row
++){
854 /* Print the hex offset */
855 sprintf (hex_buff
, "%05X", (int) (from
- view
->first
));
856 widget_move (view
, row
, frame_shift
);
857 view_add_string (view
, hex_buff
);
859 /* Hex dump starts from column seven */
862 /* Each hex number is two digits */
864 for (bytes
= 0; bytes
< view
->bytes_per_line
865 && from
< view
->last_byte
; bytes
++, from
++){
866 /* Display and mark changed bytes */
867 if (curr
&& from
== curr
->offset
) {
871 view_set_color (view
, 7);
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
){
878 view_set_color (view
, BOLD_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
;
887 view_set_color (view
, view
->view_side
== view_side_left
? PICK_COLOR (15, 31));
890 /* Print a hex number (sprintf is too slow) */
891 hex_buff
[0] = hex_char
[(c
>> 4)];
892 hex_buff
[1] = hex_char
[c
& 15];
893 view_gotoyx (view
, row
, col
);
894 view_add_string (view
, hex_buff
);
896 /* Turn off the cursor or changed byte highlighting here */
898 view_set_color (view
, DEF_COLOR
);
899 if ((bytes
& 3) == 3 && bytes
+ 1 < view
->bytes_per_line
){
900 /* Turn off the search highlighting */
902 from
== view
->search_start
+ view
->found_len
- 1)
903 view_set_color (view
, DEF_COLOR
);
905 /* Hex numbers are printed in the groups of four */
906 /* Groups are separated by a vline */
908 view_add_character (view
, ' ');
910 view_gotoyx (view
, row
, col
+ 1);
913 if (boldflag
&& from
==view
->search_start
+view
->found_len
-1)
914 view_set_color (view
, BOLD_COLOR
);
917 if (boldflag
&& from
< view
->search_start
+ view
->found_len
- 1
918 && bytes
!= view
->bytes_per_line
- 1)
919 view_add_character (view
, ' ');
921 /* Print the corresponding ascii character */
922 view_gotoyx (view
, row
, text_start
+ bytes
);
924 if (!is_printable (c
))
930 view_set_color (view
, BOLD_COLOR
);
933 view_set_color (view
, view
->view_side
== view_side_left
? PICK_COLOR (31, 15));
936 view_set_color (view
, 7);
939 if (view
->view_side
== view_side_right
){
940 view
->cursor_col
= text_start
+ bytes
;
941 view
->cursor_row
= row
;
944 view_add_character (view
, c
);
948 view_set_color (view
, DEF_COLOR
);
953 if (view
->growing_buffer
&& from
== view
->last_byte
)
954 get_byte (view
, from
);
955 for (; row
< height
&& from
< view
->last_byte
; from
++){
956 c
= get_byte (view
, from
);
957 if ((c
== '\n') || (col
== width
&& view
->wrap_mode
)){
960 if (c
== '\n' || row
>= height
)
966 col
= ((col
- frame_shift
)/8)*8 + 8 + frame_shift
;
969 if (view
->viewer_nroff_flag
&& c
== '\b'){
970 if (from
+ 1 < view
->last_byte
971 && is_printable (get_byte (view
, from
+ 1)) &&
973 && is_printable (get_byte (view
, from
- 1)))
975 if (col
<= frame_shift
){
976 /* So it has to be wrap_mode - do not need to check for it */
977 if (row
== 1 + frame_shift
){
979 continue; /* There had to be a bold character on the rightmost position
980 of the previous undisplayed line */
987 if (get_byte (view
, from
- 1) == '_' && get_byte (view
, from
+ 1) != '_')
988 view_set_color (view
, UNDERLINE_COLOR
);
990 view_set_color (view
, BOLD_COLOR
);
994 if (view
->found_len
&& from
>= view
->search_start
995 && from
< view
->search_start
+ view
->found_len
){
997 view_set_color (view
, MARK_COLOR
);
999 if (col
>= frame_shift
-view
->start_col
1000 && col
< width
-view
->start_col
)
1002 view_gotoyx (view
, row
, col
+view
->start_col
);
1003 if (!is_printable (c
))
1006 view_add_character (view
, c
);
1011 view_set_color (view
, DEF_COLOR
);
1014 /* Very last thing */
1015 if (view
->growing_buffer
&& from
+1 == view
->last_byte
)
1016 get_byte (view
, from
+1);
1019 view_gotoyx (view
, view
->current_line
+1, 0);
1028 view_place_cursor (WView
*view
)
1032 if (view
->view_side
== view_side_left
)
1033 shift
= view
->nib_shift
;
1037 widget_move (&view
->widget
, view
->cursor_row
, view
->cursor_col
+ shift
);
1041 view_update (WView
*view
)
1043 static int dirt_limit
= 1;
1045 if (view
->dirty
> dirt_limit
){
1046 /* Too many updates skipped -> force a update */
1050 /* Raise the update skipping limit */
1052 if (dirt_limit
> max_dirt_limit
)
1053 dirt_limit
= max_dirt_limit
;
1057 /* We have time to update the screen properly */
1064 /* We are busy -> skipping full update,
1065 only the status line is updated */
1068 /* Here we had a refresh, if fast scrolling does not work
1069 restore the refresh, although this should not happen */
1074 my_define (Dlg_head
*h
, int idx
, char *text
,
1075 void (*fn
)(WView
*), WView
*view
)
1077 define_label_data (h
, (Widget
*) view
, idx
, text
, (buttonbarfn
) fn
, view
);
1081 /* {{{ Movement functions */
1082 /* If the last parameter is nonzero, it means we want get the count of lines
1083 from current up to the the upto position inclusive */
1085 move_forward2 (WView
*view
, long current
, int lines
, long upto
)
1091 if (view
->hex_mode
){
1092 p
= current
+ lines
* view
->bytes_per_line
;
1093 p
= (p
>= view
->last_byte
) ? current
: p
;
1095 q
= view
->edit_cursor
+ view
->bytes_per_line
;
1096 line
= q
/ view
->bytes_per_line
;
1097 col
= (view
->last_byte
-1) / view
->bytes_per_line
;
1098 view
->edit_cursor
= (line
> col
) ? view
->edit_cursor
: q
;
1099 view
->edit_cursor
= (view
->edit_cursor
< view
->last_byte
) ?
1100 view
->edit_cursor
: view
->last_byte
-1;
1101 q
= current
+ ((LINES
-2) * view
->bytes_per_line
);
1102 p
= (view
->edit_cursor
< q
) ? current
: p
;
1104 view
->edit_cursor
= (view
->edit_cursor
< p
) ?
1105 p
: view
->edit_cursor
;
1113 q
= view
->last_byte
;
1114 if (get_byte (view
, q
) != '\n')
1116 for (line
= col
= 0, p
= current
; p
< q
; p
++){
1119 if (lines
!= -1 && line
>= lines
)
1122 c
= get_byte (view
, p
);
1124 if (view
->wrap_mode
){
1126 continue; /* This characters is never displayed */
1128 col
= ((col
- view
->have_frame
)/8)*8 +8+ view
->have_frame
;
1131 if (view
->viewer_nroff_flag
&& c
== '\b'){
1132 if (p
+ 1 < view
->last_byte
1133 && is_printable (get_byte (view
, p
+ 1))
1135 && is_printable (get_byte (view
, p
- 1)))
1137 } else if (col
== vwidth
){
1138 /* FIXME: the c in is_printable was a p, that is a bug,
1139 I suspect I got that fix from Jakub, same applies
1141 int d
= get_byte (view
, p
+2);
1143 if (p
+ 2 >= view
->last_byte
|| !is_printable (c
) ||
1144 !view
->viewer_nroff_flag
|| get_byte (view
, p
+ 1) != '\b' ||
1148 if (c
== '\n' || get_byte (view
, p
+1) != '\n')
1151 } else if (c
== '\n'){
1155 } else if (c
== '\n')
1164 /* returns the new current pointer */
1165 /* Cause even the forward routine became very complex, we in the wrap_mode
1166 just find the nearest '\n', use move_forward2(p, 0, q) to get the count
1167 of lines up to there and then use move_forward2(p, something, 0), which we
1170 move_backward2 (WView
*view
, long current
, int lines
)
1175 if (!view
->hex_mode
&& current
== view
->first
)
1178 if (view
->hex_mode
){
1179 p
= current
- lines
* view
->bytes_per_line
;
1180 p
= (p
< view
->first
) ? view
->first
: p
;
1182 q
= view
->edit_cursor
- view
->bytes_per_line
;
1183 view
->edit_cursor
= (q
< view
->first
) ? view
->edit_cursor
: q
;
1184 p
= (view
->edit_cursor
>= current
) ? current
: p
;
1186 q
= p
+ ((LINES
-2) * view
->bytes_per_line
);
1187 view
->edit_cursor
= (view
->edit_cursor
>= q
) ?
1188 p
: view
->edit_cursor
;
1192 if (current
== view
->last_byte
1193 && get_byte (view
, current
- 1) != '\n')
1194 /* There is one virtual '\n' at the end,
1195 so that the last line is shown */
1199 for (q
= p
= current
- 1; p
>= view
->first
; p
--)
1200 if (get_byte (view
, p
) == '\n' || p
== view
->first
) {
1201 pm
= p
> view
->first
? p
+ 1 : view
->first
;
1202 if (!view
->wrap_mode
){
1207 line
+= move_forward2 (view
, pm
, 0, q
);
1212 return move_forward2 (view
, pm
, line
- lines
, 0);
1218 return p
> view
->first
? p
: view
->first
;
1222 view_move_backward (WView
*view
, int i
)
1224 view
->search_start
= view
->start_display
=
1225 move_backward2 (view
, view
->start_display
, i
);
1226 view
->found_len
= 0;
1227 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1232 get_bottom_first (WView
*view
, int do_not_cache
, int really
)
1236 if (!have_fast_cpu
&& !really
)
1239 if (!do_not_cache
&& view
->bottom_first
!= -1)
1240 return view
->bottom_first
;
1243 if (view
->growing_buffer
){
1247 while (old_last_byte
!= view
->last_byte
){
1248 old_last_byte
= view
->last_byte
;
1249 get_byte (view
, view
->last_byte
+VIEW_PAGE_SIZE
);
1253 bottom_first
= move_backward2 (view
, view
->last_byte
, vheight
- 1);
1256 bottom_first
= (bottom_first
+ view
->bytes_per_line
- 1)
1257 / view
->bytes_per_line
* view
->bytes_per_line
;
1258 view
->bottom_first
= bottom_first
;
1260 return view
->bottom_first
;
1264 view_move_forward (WView
*view
, int i
)
1266 view
->start_display
= move_forward2 (view
, view
->start_display
, i
, 0);
1267 if (!view
->reading_pipe
&& view
->start_display
> get_bottom_first (view
, 0, 0))
1268 view
->start_display
= view
->bottom_first
;
1269 view
->search_start
= view
->start_display
;
1270 view
->found_len
= 0;
1271 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1277 move_to_top (WView
*view
)
1279 view
->search_start
= view
->start_display
= view
->first
;
1280 view
->found_len
= 0;
1281 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1282 view
->nib_shift
= 0;
1283 view
->edit_cursor
= view
->start_display
;
1288 move_to_bottom (WView
*view
)
1290 view
->search_start
= view
->start_display
= get_bottom_first (view
, 0, 1);
1291 view
->found_len
= 0;
1292 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1293 view
->edit_cursor
= (view
->edit_cursor
< view
->start_display
) ?
1294 view
->start_display
: view
->edit_cursor
;
1298 /* Scroll left/right the view panel functions */
1300 move_right (WView
*view
)
1302 if (view
->wrap_mode
&& !view
->hex_mode
)
1304 if (view
->hex_mode
) {
1305 view
->last
= view
->first
+ ((LINES
-2) * view
->bytes_per_line
);
1307 if (view
->hex_mode
&& view
->view_side
== view_side_left
) {
1308 view
->nib_shift
= 1 - view
->nib_shift
;
1309 if (view
->nib_shift
== 1)
1312 view
->edit_cursor
= (++view
->edit_cursor
< view
->last_byte
) ?
1313 view
->edit_cursor
: view
->last_byte
- 1;
1314 if (view
->edit_cursor
>= view
->last
) {
1315 view
->edit_cursor
-= view
->bytes_per_line
;
1316 view_move_forward(view
, 1);
1319 if (--view
->start_col
> 0)
1320 view
->start_col
= 0;
1325 move_left (WView
*view
)
1327 if (view
->wrap_mode
&& !view
->hex_mode
)
1329 if (view
->hex_mode
) {
1330 if (view
->hex_mode
&& view
->view_side
== view_side_left
) {
1331 view
->nib_shift
= 1 - view
->nib_shift
;
1332 if (view
->nib_shift
== 0)
1335 view
->edit_cursor
= (--view
->edit_cursor
< view
->first
) ?
1336 view
->first
: view
->edit_cursor
;
1337 if (view
->edit_cursor
< view
->start_display
) {
1338 view
->edit_cursor
+= view
->bytes_per_line
;
1339 view_move_backward(view
, 1);
1342 if (++view
->start_col
> 0)
1343 view
->start_col
= 0;
1348 /* {{{ Search routines */
1350 /* Case insensitive search of text in data */
1352 icase_search_p (WView
*view
, char *text
, char *data
, int nothing
)
1357 p
= (q
= _icase_search (text
, data
, &lng
)) != 0;
1359 view
->found_len
= lng
;
1360 view
->search_start
= q
- data
- view
->found_len
;
1366 grow_string_buffer (char *text
, int *size
)
1369 int old_size
= *size
;
1371 /* The grow steps */
1373 new = xmalloc (*size
, "grow_string_buffer");
1375 strncpy (new, text
, old_size
);
1384 get_line_at (WView
*view
, long *p
)
1387 int buffer_size
, usable_size
;
1393 direction
= view
->direction
;
1394 buffer_size
= usable_size
= 0;
1397 for (;pos
>= 0 && (ch
= get_byte (view
, pos
))!= -1; pos
+= direction
, i
++){
1399 /* skip over all the possible zeros in the file */
1400 if (ch
== 0 && i
== 0){
1401 while (pos
>= 0 && ((ch
= get_byte (view
, pos
)) != -1) && ch
== 0)
1406 if (i
== usable_size
){
1407 buffer
= grow_string_buffer (buffer
, &buffer_size
);
1408 usable_size
= buffer_size
- 2;
1409 buffer
[0] = ' '; /* This makes possible strcpy of buffer */
1412 if (ch
== '\n' || !ch
|| ch
== -1){
1413 pos
+= direction
; i
++;
1422 /* If we are searching backwards, reverse the string */
1423 if (view
->direction
< 0)
1424 reverse_string (buffer
);
1431 /** Search status optmizations **/
1433 /* The number of bytes between percent increments */
1436 /* Last point where we updated the status */
1437 long update_activate
;
1440 search_update_steps (WView
*view
)
1442 if (view
->s
.st_size
)
1443 update_steps
= 40000;
1445 update_steps
= view
->last_byte
/ 100;
1447 /* Do not update the percent display but every 20 ks */
1448 if (update_steps
< 20000)
1449 update_steps
= 20000;
1453 search (WView
*view
, char *text
, int (*search
)(WView
*, char *, char *, int))
1455 int w
= view
->widget
.cols
- (view
->have_frame
* 2);
1456 char *s
= NULL
; /* The line we read from the view buffer */
1459 int isatbeg
; /* Nonzero means we start search at beginning of some line */
1460 int found_len
, search_start
;
1464 /* Used to keep track of where the line starts, when looking forward */
1465 /* is the index before transfering the line; the reverse case uses */
1466 /* the position returned after the line has been read */
1467 long forward_line_start
;
1468 long reverse_line_start
;
1470 /* Clear interrupt status */
1474 d
= message (D_INSERT
, _(" Search "), _("Searching %s"), text
);
1478 if (view
->direction
== 1){
1479 p
= view
->found_len
? view
->search_start
+ 1 : view
->search_start
;
1481 p
= (view
->found_len
? view
->search_start
: view
->last
) - 1;
1485 isatbeg
= view
->found_len
== 0;
1486 found_len
= view
->found_len
;
1487 search_start
= view
->search_start
;
1489 /* Compute the percent steps */
1490 search_update_steps (view
);
1491 update_activate
= 0;
1493 for (; ; isatbeg
= 1, free (s
)){
1494 #ifdef PORT_HAS_FLUSH_EVENTS
1497 if ((count
++ % 32) == 0)
1502 if (p
>= update_activate
){
1503 update_activate
+= update_steps
;
1505 view_percent (view
, p
, w
);
1508 if (got_interrupt ())
1511 forward_line_start
= p
;
1512 disable_interrupt_key ();
1513 s
= get_line_at (view
, &p
);
1514 reverse_line_start
= p
;
1515 enable_interrupt_key ();
1519 search_status
= (*search
) (view
, text
, s
+ 1, match_normal
);
1520 if (search_status
< 0)
1523 if (search_status
== 0)
1526 /* We found the string */
1528 if (!isatbeg
&& !view
->search_start
){
1530 /* We do not want to match a
1531 * ^ regexp when not at the real
1532 * beginning of some line
1534 view
->found_len
= found_len
;
1535 view
->search_start
= search_start
;
1536 if ((*search
) (view
, text
, s
, match_normal
) <= 0)
1538 (*search
) (view
, text
, s
+ 1, match_normal
);
1540 /* Record the position used to continue the search */
1541 if (view
->direction
== 1)
1542 t
= forward_line_start
;
1544 t
= reverse_line_start
? reverse_line_start
+ 3 : 0;
1545 view
->search_start
+= t
;
1547 if (t
!= beginning
){
1548 if (t
> get_bottom_first (view
, 0, 0))
1549 view
->start_display
= view
->bottom_first
;
1551 view
->start_display
= t
;
1557 disable_interrupt_key ();
1564 message (0, _(" Search "), _(" Search string not found "));
1565 view
->found_len
= 0;
1569 /* Search buffer (it's size is len) in the complete buffer */
1570 /* returns the position where the block was found or -1 if not found */
1572 block_search (WView
*view
, char *buffer
, int len
)
1574 int w
= view
->widget
.cols
- (view
->have_frame
* 2);
1575 char *d
= buffer
, b
;
1578 /* clear interrupt status */
1580 enable_interrupt_key ();
1581 e
= view
->found_len
? view
->search_start
+ 1 : view
->search_start
;
1583 search_update_steps (view
);
1584 update_activate
= 0;
1586 for (; e
< view
->last_byte
; e
++){
1587 if (e
>= update_activate
){
1588 update_activate
+= update_steps
;
1590 view_percent (view
, e
, w
);
1593 if (got_interrupt ())
1596 b
= get_byte (view
, e
);
1604 if (d
- buffer
== len
){
1605 disable_interrupt_key ();
1609 disable_interrupt_key ();
1613 /* States of our funny recognizer */
1623 /* This routine doesn't report all the user mistakes, it just ignores them */
1625 hex_search (WView
*view
, char *text
)
1627 char buffer
[120]; /* Where we hold the information */
1630 long pos
; /* Where did we found the string */
1631 char *p
; /* Temporary */
1632 int state
= normal
; /* Initial state of the micro-scanner */
1634 /* First convert the string to a stream of bytes */
1635 for (i
= block_len
= 0; text
[i
] && block_len
< sizeof (buffer
); i
++){
1638 if (text
[i
] == '"')
1641 buffer
[block_len
++] = text
[i
];
1645 if (text
[i
] == '"'){
1646 state
= inside_quotes
;
1649 if (text
[i
] == '0'){
1653 if (text
[i
] == 'x'){
1660 if (text
[i
] == 'x')
1666 text
[i
] = toupper (text
[i
]);
1667 if ((p
= strchr (hex_char
, text
[i
])) != 0){
1668 v
= (p
- hex_char
) << 4;
1674 text
[i
] = toupper (text
[i
]);
1675 if ((p
= strchr (hex_char
, text
[i
])) != 0){
1676 v
|= (p
- hex_char
);
1679 buffer
[block_len
++] = v
;
1683 /* Then start the search */
1684 pos
= block_search (view
, buffer
, block_len
);
1686 message (0, _(" Search "), _(" Search string not found "));
1687 view
->found_len
= 0;
1691 view
->search_start
= pos
+ 1;
1692 view
->found_len
= block_len
;
1693 /* Set the edit cursor to the search position, left nibble */
1694 view
->edit_cursor
= view
->search_start
;
1695 view
->nib_shift
= 0;
1697 /* Adjust the file offset */
1698 view
->start_display
= (pos
& (~(view
->bytes_per_line
-1)));
1699 if (view
->start_display
> get_bottom_first (view
, 0, 0))
1700 view
->start_display
= view
->bottom_first
;
1703 static int regexp_view_search (WView
*view
, char *pattern
, char *string
, int match_type
)
1706 static char *old_pattern
= NULL
;
1707 static int old_type
;
1708 regmatch_t pmatch
[1];
1709 int i
, flags
= REG_ICASE
;
1711 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
){
1717 for (i
= 0; pattern
[i
] != 0; i
++){
1718 if (isupper ((unsigned char) pattern
[i
])){
1723 flags
|= REG_EXTENDED
;
1724 if (regcomp (&r
, pattern
, flags
)){
1725 message (1, MSG_ERROR
, _(" Invalid regular expression "));
1728 old_pattern
= strdup (pattern
);
1729 old_type
= match_type
;
1731 if (regexec (&r
, string
, 1, pmatch
, 0) != 0)
1733 view
->found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1734 view
->search_start
= pmatch
[0].rm_so
;
1738 static void do_regexp_search (void *xview
, char *regexp
)
1740 WView
*view
= (WView
*) xview
;
1742 view
->search_exp
= regexp
;
1743 search (view
, regexp
, regexp_view_search
);
1744 /* Had a refresh here */
1749 static void do_normal_search (void *xview
, char *text
)
1751 WView
*view
= (WView
*) xview
;
1753 view
->search_exp
= text
;
1755 hex_search (view
, text
);
1757 search (view
, text
, icase_search_p
);
1758 /* Had a refresh here */
1764 /* {{{ Mouse and keyboard handling */
1766 /* Real view only */
1767 static void help_cmd (void)
1769 char *hlpfile
= concat_dir_and_file (mc_home
, "mc.hlp");
1770 interactive_display (hlpfile
, "[Internal File Viewer]");
1778 void toggle_wrap_mode (WView
*view
)
1780 if (view
->hex_mode
) {
1781 if (view
->growing_buffer
!= 0) {
1784 get_bottom_first (view
, 1, 1);
1785 if (view
->hexedit_mode
) {
1786 view
->view_side
= 1 - view
->view_side
;
1788 view
->hexedit_mode
= 1 - view
->hexedit_mode
;
1795 view
->wrap_mode
= 1 - view
->wrap_mode
;
1796 get_bottom_first (view
, 1, 1);
1797 if (view
->wrap_mode
)
1798 view
->start_col
= 0;
1801 if (view
->bottom_first
< view
->start_display
)
1802 view
->search_start
= view
->start_display
= view
->bottom_first
;
1803 view
->found_len
= 0;
1813 toggle_hex_mode (WView
*view
)
1815 view
->hex_mode
= 1 - view
->hex_mode
;
1817 if (view
->hex_mode
){
1818 /* Shift the line start to 0x____0 on entry, restore it for Ascii */
1819 view
->start_save
= view
->start_display
;
1820 view
->start_display
-= view
->start_display
% view
->bytes_per_line
;
1821 view
->edit_cursor
= view
->start_display
;
1822 view
->widget
.options
|= W_WANT_CURSOR
;
1823 view
->widget
.parent
->raw
= 1;
1825 view
->start_display
= view
->start_save
;
1826 view
->widget
.parent
->raw
= 0;
1827 view
->widget
.options
&= ~W_WANT_CURSOR
;
1829 altered_hex_mode
= 1;
1830 get_bottom_first (view
, 1, 1);
1838 toggle_hexedit_mode(WView
*view
)
1840 view
->hexedit_mode
= 1 - view
->hexedit_mode
;
1845 goto_line (WView
*view
)
1847 char *line
, prompt
[100];
1849 int saved_wrap_mode
= view
->wrap_mode
;
1851 view
->wrap_mode
= 0;
1852 for (i
= view
->first
; i
< view
->start_display
; i
++)
1853 if (get_byte (view
, i
) == '\n')
1855 sprintf (prompt
, _(" The current line number is %d.\n"
1856 " Enter the new line number:"), oldline
);
1857 line
= input_dialog (_(" Goto line "), prompt
, "");
1861 view_move_forward (view
, atoi (line
) - 1);
1866 view
->wrap_mode
= saved_wrap_mode
;
1872 regexp_search (WView
*view
, int direction
)
1875 static char *old
= 0;
1877 /* This is really an F6 key handler */
1878 if (view
->hex_mode
){
1879 /* Save it without a confirmation prompt */
1880 save_edit_changes(view
);
1884 regexp
= old
? old
: regexp
;
1885 regexp
= input_dialog (_(" Search "), _(" Enter regexp:"), regexp
);
1886 if ((!regexp
) || (!*regexp
)){
1893 /* Mhm, do we really need to load all the file in the core? */
1894 if (view
->bytes_read
< view
->last_byte
)
1895 get_byte (view
, view
->last_byte
-1);/* Get the whole file in to memory */
1897 view
->direction
= direction
;
1898 do_regexp_search (view
, regexp
);
1900 view
->last_search
= do_regexp_search
;
1904 regexp_search_cmd (WView
*view
)
1906 regexp_search (view
, 1);
1911 normal_search (WView
*view
, int direction
)
1916 exp
= old
? old
: exp
;
1917 exp
= input_dialog (_(" Search "), _(" Enter search string:"), exp
);
1918 if ((!exp
) || (!*exp
)){
1925 view
->direction
= direction
;
1926 do_normal_search (view
, exp
);
1927 view
->last_search
= do_normal_search
;
1931 normal_search_cmd (WView
*view
)
1933 normal_search (view
, 1);
1937 change_viewer (WView
*view
)
1943 if (*view
->filename
) {
1944 altered_magic_flag
= 1;
1945 view
->viewer_magic_flag
= !view
->viewer_magic_flag
;
1946 s
= strdup (view
->filename
);
1948 t
= strdup (view
->command
);
1953 view_init (view
, t
, s
, 0);
1964 change_nroff (WView
*view
)
1966 view
->viewer_nroff_flag
= !view
->viewer_nroff_flag
;
1967 altered_nroff_flag
= 1;
1973 /* Real view only */
1975 view_quit_cmd (WView
*view
)
1977 if (view_ok_to_quit (view
))
1978 dlg_stop (view
->widget
.parent
);
1983 view_labels (WView
*view
)
1985 Dlg_head
*h
= view
->widget
.parent
;
1987 define_label (h
, (Widget
*) view
, 1, _("Help"), help_cmd
);
1989 my_define (h
, 10, _("Quit"), view_quit_cmd
, view
);
1990 my_define (h
, 4, view
->hex_mode
? _("Ascii"): _("Hex"), toggle_hex_mode
, view
);
1991 my_define (h
, 5, _("Line"), goto_line
, view
);
1992 my_define (h
, 6, view
->hex_mode
? _("Save") : _("RxSrch"), regexp_search_cmd
, view
);
1994 my_define (h
, 2, view
->hex_mode
? view
->hexedit_mode
?
1995 view
->view_side
== view_side_left
? _("EdText") : _("EdHex") :
1996 view
->growing_buffer
? "" : _("Edit") :
1997 view
->wrap_mode
? _("UnWrap") : _("Wrap"),
1998 toggle_wrap_mode
, view
);
2000 my_define (h
, 7, view
->hex_mode
? _("HxSrch") : _("Search"),
2001 normal_search_cmd
, view
);
2003 my_define (h
, 8, view
->viewer_magic_flag
? _("Raw") : _("Parse"),
2004 change_viewer
, view
);
2006 if (!view
->have_frame
){
2007 my_define (h
, 9, view
->viewer_nroff_flag
? _("Unform") : _("Format"),
2008 change_nroff
, view
);
2009 my_define (h
, 3, _("Quit"), view_quit_cmd
, view
);
2012 redraw_labels (h
, (Widget
*) view
);
2017 check_left_right_keys (WView
*view
, int c
)
2021 else if (c
== KEY_RIGHT
)
2029 set_monitor (WView
*view
, int set_on
)
2031 int old
= view
->monitor
;
2033 view
->monitor
= set_on
;
2036 move_to_bottom (view
);
2037 view
->bottom_first
= -1;
2038 set_idle_proc (view
->widget
.parent
, 1);
2041 set_idle_proc (view
->widget
.parent
, 0);
2046 continue_search (WView
*view
)
2048 if (view
->last_search
){
2049 (*view
->last_search
)(view
, view
->search_exp
);
2051 /* if not... then ask for an expression */
2052 normal_search (view
, 1);
2058 view_handle_key (WView
*view
, int c
)
2060 int prev_monitor
= view
->monitor
;
2062 set_monitor (view
, off
);
2064 if (view
->hex_mode
) {
2066 case 0x09: /* Tab key */
2067 view
->view_side
= 1 - view
->view_side
;
2071 case XCTRL('a'): /* Beginning of line */
2072 view
->edit_cursor
-= view
->edit_cursor
% view
->bytes_per_line
;
2076 case XCTRL('b'): /* Character back */
2080 case XCTRL('e'): /* End of line */
2081 view
->edit_cursor
-= view
->edit_cursor
% view
->bytes_per_line
;
2082 view
->edit_cursor
+= view
->bytes_per_line
- 1;
2086 case XCTRL('f'): /* Character forward */
2091 /* Trap 0-9,A-F,a-f for left side data entry (hex editing) */
2092 if (view
->view_side
== view_side_left
){
2093 if ((c
>= '0' && c
<= '9') ||
2094 (c
>= 'A' && c
<= 'F') ||
2095 (c
>= 'a' && c
<= 'f')){
2097 put_editkey (view
, c
);
2102 /* Trap all printable characters for right side data entry */
2103 /* Also enter the value of the Enter key */
2104 if (view
->view_side
== view_side_right
){
2105 if (c
< 256 && (is_printable (c
) || (c
== '\n'))){
2106 put_editkey(view
, c
);
2112 if (check_left_right_keys (view
, c
))
2115 if (check_movement_keys (c
, 1, vheight
, view
, (movefn
) view_move_backward
, (movefn
) view_move_forward
,
2116 (movefn
) move_to_top
, (movefn
) move_to_bottom
)){
2122 regexp_search (view
, -1);
2126 regexp_search (view
, 1);
2129 /* Continue search */
2133 continue_search (view
);
2137 if (view
->last_search
){
2138 (*view
->last_search
)(view
, view
->search_exp
);
2140 normal_search (view
, -1);
2164 view_move_forward (view
, 1);
2168 view_move_forward (view
, vheight
/ 2);
2172 view_move_backward (view
, vheight
/ 2);
2177 view_move_backward (view
, 1);
2186 view_move_forward (view
, vheight
- 1);
2194 set_monitor (view
, on
);
2198 view_move_backward (view
, vheight
- 1);
2202 view_move_backward (view
, 2);
2206 view_move_forward (view
, 2);
2210 view
->marks
[view
->marker
] = view
->start_display
;
2214 view
->start_display
= view
->marks
[view
->marker
];
2218 /* Use to indicate parent that we want to see the next/previous file */
2219 /* Only works on full screen mode */
2222 if (!view
->have_frame
)
2223 view
->move_dir
= c
== XCTRL('f') ? 1 : -1;
2229 if (view_ok_to_quit (view
))
2230 view
->view_quit
= 1;
2234 if (c
>= '0' && c
<= '9')
2235 view
->marker
= c
- '0';
2237 /* Restore the monitor status */
2238 set_monitor (view
, prev_monitor
);
2246 view_event (WView
*view
, Gpm_Event
*event
, int *result
)
2248 *result
= MOU_NORMAL
;
2249 if (event
->type
& (GPM_DOWN
|GPM_DRAG
)){
2250 if (!view
->wrap_mode
){
2251 if (event
->x
< view
->widget
.cols
/ 4){
2253 *result
= MOU_REPEAT
;
2256 if (event
->x
> 3 * vwidth
/ 4){
2258 *result
= MOU_REPEAT
;
2262 if (event
->y
< view
->widget
.lines
/ 3){
2263 if (mouse_move_pages_viewer
)
2264 view_move_backward (view
, view
->widget
.lines
/ 2 - 1);
2266 view_move_backward (view
, 1);
2267 *result
= MOU_REPEAT
;
2270 else if (event
->y
> 2 * vheight
/3){
2271 if (mouse_move_pages_viewer
)
2272 view_move_forward (view
, vheight
/ 2 - 1);
2274 view_move_forward (view
, 1);
2275 *result
= MOU_REPEAT
;
2282 /* Real view only */
2284 real_view_event (Gpm_Event
*event
, void *x
)
2288 if (view_event ((WView
*) x
, event
, &result
))
2289 view_update ((WView
*) x
);
2294 /* {{{ Window creation, destruction and a driver stub for real view */
2297 view_mode_callback (struct Dlg_head
*h
, int id
, int msg
)
2299 return default_dlg_callback (h
, id
, msg
);
2303 /* Real view only */
2306 view_adjust_size (Dlg_head
*unused
)
2311 view (char *_command
, char *_file
, int *move_dir_p
, int start_line
)
2313 int midnight_colors
[4];
2317 wview
= view_new (0, 0, COLS
, LINES
- 1, 0);
2319 error
= view_init (wview
, _command
, _file
, start_line
);
2328 #ifndef PORT_WANTS_VIEW
2330 view_adjust_size (Dlg_head
*h
)
2335 /* Look up the viewer and the buttonbar, we assume only two widgets here */
2336 view
= (WView
*) find_widget_type (h
, (callback_fn
) view_callback
);
2337 bar
= (WButtonBar
*) view
->widget
.parent
->current
->next
->widget
;
2338 widget_set_size (&view
->widget
, 0, 0, LINES
-1, COLS
);
2339 widget_set_size (&bar
->widget
, LINES
-1, 0, 1, COLS
);
2342 /* Only the text mode edition uses this */
2345 /* Real view only */
2347 view (char *_command
, char *_file
, int *move_dir_p
, int start_line
)
2349 int midnight_colors
[4];
2355 /* Create dialog and widgets, put them on the dialog */
2356 our_dlg
= create_dlg (0, 0, LINES
, COLS
, midnight_colors
,
2357 view_mode_callback
, "[Internal File Viewer]",
2364 wview
= view_new (0, 0, COLS
, LINES
-1, 0);
2366 bar
= buttonbar_new (1);
2368 add_widget (our_dlg
, wview
);
2369 add_widget (our_dlg
, bar
);
2371 error
= view_init (wview
, _command
, _file
, start_line
);
2375 /* Please note that if you add another widget,
2376 * you have to modify view_adjust_size to
2382 *move_dir_p
= wview
->move_dir
;
2384 destroy_dlg (our_dlg
);
2393 WView
*view
= (WView
*) v
;
2397 /* If the user is busy typing, wait until he finishes to update the
2400 if (!hook_present (idle_hook
, view_hook
))
2401 add_hook (&idle_hook
, view_hook
, v
);
2405 delete_hook (&idle_hook
, view_hook
);
2407 if (get_current_type () == view_listing
)
2409 else if (get_other_type () == view_listing
)
2410 panel
= other_panel
;
2414 if (S_ISLNK (panel
->dir
.list
[panel
->selected
].buf
.st_mode
)){
2415 if (mc_stat (panel
->dir
.list
[panel
->selected
].fname
, &s
) != 0)
2417 if (!S_ISREG (s
.st_mode
))
2420 if (!S_ISREG (panel
->dir
.list
[panel
->selected
].buf
.st_mode
))
2424 view_init (view
, 0, panel
->dir
.list
[panel
->selected
].fname
, 0);
2430 view_callback (Dlg_head
*h
, WView
*v
, int msg
, int par
)
2432 WView
*view
= (WView
*) v
;
2437 x_create_viewer (view
);
2438 if (view
->have_frame
)
2439 add_hook (&select_file_hook
, view_hook
, view
);
2451 view_place_cursor (view
);
2455 i
= view_handle_key ((WView
*)view
, par
);
2456 if (view
->view_quit
)
2464 /* This event is generated when the user is using the 'F' flag */
2465 view
->bottom_first
= -1;
2466 move_to_bottom (view
);
2473 x_focus_view (view
);
2478 return default_proc (h
, msg
, par
);
2482 view_new (int y
, int x
, int cols
, int lines
, int is_panel
)
2484 WView
*view
= xmalloc (sizeof (WView
), "view_new");
2486 init_widget (&view
->widget
, y
, x
, lines
, cols
,
2487 (callback_fn
) view_callback
,
2488 (destroy_fn
) view_destroy
,
2489 (mouse_h
) real_view_event
, NULL
);
2492 view
->view_active
= 0;
2493 view
->bottom_first
= 0;
2494 view
->start_col
= 0;
2496 view
->hex_mode
= default_hex_mode
;
2497 view
->hexedit_mode
= default_hexedit_mode
;
2498 view
->viewer_magic_flag
= default_magic_flag
;
2499 view
->viewer_nroff_flag
= default_nroff_flag
;
2500 view
->view_quit
= 0;
2502 view
->have_frame
= is_panel
;
2503 view
->last_byte
= -1;
2505 view
->wrap_mode
= global_wrap_mode
;
2509 widget_want_cursor (view
->widget
, 0);
2515 /* {{{ Emacs local variables */
2517 Cause emacs to enter folding mode for this file: