This source file includes following definitions.
- mcview_remove_ext_script
- mcview_search
- mcview_continue_search_cmd
- mcview_hook
- mcview_handle_editkey
- mcview_load_next_prev_init
- mcview_scan_for_file
- mcview_load_next_prev
- mcview_load_file_from_history
- mcview_execute_cmd
- mcview_lookup_key
- mcview_handle_key
- mcview_resize
- mcview_ok_to_quit
- mcview_callback
- mcview_dialog_callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #include <config.h>
46
47 #include <errno.h>
48 #include <stdlib.h>
49
50 #include "lib/global.h"
51
52 #include "lib/tty/tty.h"
53 #include "lib/tty/key.h"
54 #include "lib/lock.h"
55 #include "lib/util.h"
56 #include "lib/widget.h"
57 #ifdef HAVE_CHARSET
58 #include "lib/charsets.h"
59 #endif
60 #include "lib/event.h"
61 #include "lib/mcconfig.h"
62
63 #include "src/filemanager/layout.h"
64 #include "src/filemanager/filemanager.h"
65 #include "src/filemanager/ext.h"
66
67 #include "src/history.h"
68 #include "src/file_history.h"
69 #include "src/execute.h"
70 #include "src/keybind-defaults.h"
71
72 #include "internal.h"
73
74
75
76
77
78
79
80
81
82
83
84
85
86 static void
87 mcview_remove_ext_script (WView * view)
88 {
89 if (view->ext_script != NULL)
90 {
91 mc_unlink (view->ext_script);
92 vfs_path_free (view->ext_script);
93 view->ext_script = NULL;
94 }
95 }
96
97
98
99
100 static void
101 mcview_search (WView * view, gboolean start_search)
102 {
103 off_t want_search_start = view->search_start;
104
105 if (start_search)
106 {
107 if (mcview_dialog_search (view))
108 {
109 if (view->mode_flags.hex)
110 want_search_start = view->hex_cursor;
111
112 mcview_do_search (view, want_search_start);
113 }
114 }
115 else
116 {
117 if (view->mode_flags.hex)
118 {
119 if (!mcview_search_options.backwards)
120 want_search_start = view->hex_cursor + 1;
121 else if (view->hex_cursor > 0)
122 want_search_start = view->hex_cursor - 1;
123 else
124 want_search_start = 0;
125 }
126
127 mcview_do_search (view, want_search_start);
128 }
129 }
130
131
132
133 static void
134 mcview_continue_search_cmd (WView * view)
135 {
136 if (view->last_search_string != NULL)
137 mcview_search (view, FALSE);
138 else
139 {
140
141 GList *history;
142
143 history = mc_config_history_get (MC_HISTORY_SHARED_SEARCH);
144 if (history != NULL && history->data != NULL)
145 {
146 view->last_search_string = (gchar *) g_strdup (history->data);
147 history = g_list_first (history);
148 g_list_free_full (history, g_free);
149
150 #ifdef HAVE_CHARSET
151 view->search = mc_search_new (view->last_search_string, cp_source);
152 #else
153 view->search = mc_search_new (view->last_search_string, NULL);
154 #endif
155 view->search_nroff_seq = mcview_nroff_seq_new (view);
156
157 if (view->search == NULL)
158 {
159
160 MC_PTR_FREE (view->last_search_string);
161 mcview_search (view, TRUE);
162 }
163 else
164 {
165 view->search->search_type = mcview_search_options.type;
166 #ifdef HAVE_CHARSET
167 view->search->is_all_charsets = mcview_search_options.all_codepages;
168 #endif
169 view->search->is_case_sensitive = mcview_search_options.case_sens;
170 view->search->whole_words = mcview_search_options.whole_words;
171 view->search->search_fn = mcview_search_cmd_callback;
172 view->search->update_fn = mcview_search_update_cmd_callback;
173
174 mcview_search (view, FALSE);
175 }
176 }
177 else
178 {
179
180 MC_PTR_FREE (view->last_search_string);
181 mcview_search (view, TRUE);
182 }
183 }
184 }
185
186
187
188 static void
189 mcview_hook (void *v)
190 {
191 WView *view = (WView *) v;
192 WPanel *panel;
193
194
195
196 if (!is_idle ())
197 {
198 if (!hook_present (idle_hook, mcview_hook))
199 add_hook (&idle_hook, mcview_hook, v);
200 return;
201 }
202
203 delete_hook (&idle_hook, mcview_hook);
204
205 if (get_current_type () == view_listing)
206 panel = current_panel;
207 else if (get_other_type () == view_listing)
208 panel = other_panel;
209 else
210 return;
211
212 mcview_done (view);
213 mcview_init (view);
214 mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0, 0, 0);
215 mcview_display (view);
216 }
217
218
219
220 static cb_ret_t
221 mcview_handle_editkey (WView * view, int key)
222 {
223 struct hexedit_change_node *node;
224 int byte_val = -1;
225
226
227 node = view->change_list;
228 while ((node != NULL) && (node->offset != view->hex_cursor))
229 node = node->next;
230
231 if (!view->hexview_in_text)
232 {
233
234 unsigned int hexvalue = 0;
235
236 if (key >= '0' && key <= '9')
237 hexvalue = 0 + (key - '0');
238 else if (key >= 'A' && key <= 'F')
239 hexvalue = 10 + (key - 'A');
240 else if (key >= 'a' && key <= 'f')
241 hexvalue = 10 + (key - 'a');
242 else
243 return MSG_NOT_HANDLED;
244
245 if (node != NULL)
246 byte_val = node->value;
247 else
248 mcview_get_byte (view, view->hex_cursor, &byte_val);
249
250 if (view->hexedit_lownibble)
251 byte_val = (byte_val & 0xf0) | (hexvalue);
252 else
253 byte_val = (byte_val & 0x0f) | (hexvalue << 4);
254 }
255 else
256 {
257
258 if (key < 256 && key != '\t')
259 byte_val = key;
260 else
261 return MSG_NOT_HANDLED;
262 }
263
264 if ((view->filename_vpath != NULL)
265 && (*(vfs_path_get_last_path_str (view->filename_vpath)) != '\0')
266 && (view->change_list == NULL))
267 view->locked = lock_file (view->filename_vpath);
268
269 if (node == NULL)
270 {
271 node = g_new (struct hexedit_change_node, 1);
272 node->offset = view->hex_cursor;
273 node->value = byte_val;
274 mcview_enqueue_change (&view->change_list, node);
275 }
276 else
277 node->value = byte_val;
278
279 view->dirty++;
280 mcview_move_right (view, 1);
281
282 return MSG_HANDLED;
283 }
284
285
286
287 static void
288 mcview_load_next_prev_init (WView * view)
289 {
290 if (mc_global.mc_run_mode != MC_RUN_VIEWER)
291 {
292
293 view->dir = ¤t_panel->dir;
294 view->dir_idx = ¤t_panel->selected;
295 }
296 else if (view->dir == NULL)
297 {
298
299
300
301
302
303 dir_sort_options_t sort_op = { FALSE, TRUE, FALSE };
304
305
306 view->dir = g_new0 (dir_list, 1);
307 view->dir_idx = g_new (int, 1);
308
309 if (dir_list_load
310 (view->dir, view->workdir_vpath, (GCompareFunc) sort_name, &sort_op, NULL))
311 {
312 const char *fname;
313 size_t fname_len;
314 int i;
315
316 fname = x_basename (vfs_path_as_str (view->filename_vpath));
317 fname_len = strlen (fname);
318
319
320 for (i = 0; i != view->dir->len; i++)
321 {
322 const file_entry_t *fe = &view->dir->list[i];
323
324 if (fname_len == fe->fnamelen && strncmp (fname, fe->fname, fname_len) == 0)
325 break;
326 }
327
328 *view->dir_idx = i;
329 }
330 else
331 {
332 message (D_ERROR, MSG_ERROR, _("Cannot read directory contents"));
333 MC_PTR_FREE (view->dir);
334 MC_PTR_FREE (view->dir_idx);
335 }
336 }
337 }
338
339
340
341 static void
342 mcview_scan_for_file (WView * view, int direction)
343 {
344 int i;
345
346 for (i = *view->dir_idx + direction; i != *view->dir_idx; i += direction)
347 {
348 if (i < 0)
349 i = view->dir->len - 1;
350 if (i == view->dir->len)
351 i = 0;
352 if (!S_ISDIR (view->dir->list[i].st.st_mode))
353 break;
354 }
355
356 *view->dir_idx = i;
357 }
358
359
360
361 static void
362 mcview_load_next_prev (WView * view, int direction)
363 {
364 dir_list *dir;
365 int *dir_idx;
366 vfs_path_t *vfile;
367 vfs_path_t *ext_script = NULL;
368
369 mcview_load_next_prev_init (view);
370 mcview_scan_for_file (view, direction);
371
372
373 dir = view->dir;
374 dir_idx = view->dir_idx;
375 view->dir = NULL;
376 view->dir_idx = NULL;
377 vfile = vfs_path_append_new (view->workdir_vpath, dir->list[*dir_idx].fname, (char *) NULL);
378 mcview_done (view);
379 mcview_remove_ext_script (view);
380 mcview_init (view);
381 if (regex_command_for (view, vfile, "View", &ext_script) == 0)
382 mcview_load (view, NULL, vfs_path_as_str (vfile), 0, 0, 0);
383 vfs_path_free (vfile);
384 view->dir = dir;
385 view->dir_idx = dir_idx;
386 view->ext_script = ext_script;
387
388 view->dpy_bbar_dirty = FALSE;
389 view->dirty++;
390 }
391
392
393
394 static void
395 mcview_load_file_from_history (WView * view)
396 {
397 char *filename;
398 int action;
399
400 filename = show_file_history (CONST_WIDGET (view), &action);
401
402 if (filename != NULL && (action == CK_View || action == CK_Enter))
403 {
404 mcview_done (view);
405 mcview_init (view);
406
407 mcview_load (view, NULL, filename, 0, 0, 0);
408
409 view->dpy_bbar_dirty = FALSE;
410 view->dirty++;
411 }
412
413 g_free (filename);
414 }
415
416
417
418 static cb_ret_t
419 mcview_execute_cmd (WView * view, long command)
420 {
421 int res = MSG_HANDLED;
422
423 switch (command)
424 {
425 case CK_Help:
426 {
427 ev_help_t event_data = { NULL, "[Internal File Viewer]" };
428 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
429 }
430 break;
431 case CK_HexMode:
432
433 mcview_toggle_hex_mode (view);
434 break;
435 case CK_HexEditMode:
436
437 mcview_toggle_hexedit_mode (view);
438 break;
439 case CK_ToggleNavigation:
440 view->hexview_in_text = !view->hexview_in_text;
441 view->dirty++;
442 break;
443 case CK_LeftQuick:
444 if (!view->mode_flags.hex)
445 mcview_move_left (view, 10);
446 break;
447 case CK_RightQuick:
448 if (!view->mode_flags.hex)
449 mcview_move_right (view, 10);
450 break;
451 case CK_Goto:
452 {
453 off_t addr;
454
455 if (mcview_dialog_goto (view, &addr))
456 {
457 if (addr >= 0)
458 mcview_moveto_offset (view, addr);
459 else
460 {
461 message (D_ERROR, _("Warning"), "%s", _("Invalid value"));
462 view->dirty++;
463 }
464 }
465 break;
466 }
467 case CK_Save:
468 mcview_hexedit_save_changes (view);
469 break;
470 case CK_Search:
471 mcview_search (view, TRUE);
472 break;
473 case CK_SearchContinue:
474 mcview_continue_search_cmd (view);
475 break;
476 case CK_SearchForward:
477 mcview_search_options.backwards = FALSE;
478 mcview_search (view, TRUE);
479 break;
480 case CK_SearchForwardContinue:
481 mcview_search_options.backwards = FALSE;
482 mcview_continue_search_cmd (view);
483 break;
484 case CK_SearchBackward:
485 mcview_search_options.backwards = TRUE;
486 mcview_search (view, TRUE);
487 break;
488 case CK_SearchBackwardContinue:
489 mcview_search_options.backwards = TRUE;
490 mcview_continue_search_cmd (view);
491 break;
492 case CK_SearchOppositeContinue:
493 {
494 gboolean direction;
495
496 direction = mcview_search_options.backwards;
497 mcview_search_options.backwards = !direction;
498 mcview_continue_search_cmd (view);
499 mcview_search_options.backwards = direction;
500 }
501 break;
502 case CK_WrapMode:
503
504 mcview_toggle_wrap_mode (view);
505 break;
506 case CK_MagicMode:
507 mcview_toggle_magic_mode (view);
508 break;
509 case CK_NroffMode:
510 mcview_toggle_nroff_mode (view);
511 break;
512 case CK_Home:
513 mcview_moveto_bol (view);
514 break;
515 case CK_End:
516 mcview_moveto_eol (view);
517 break;
518 case CK_Left:
519 mcview_move_left (view, 1);
520 break;
521 case CK_Right:
522 mcview_move_right (view, 1);
523 break;
524 case CK_Up:
525 mcview_move_up (view, 1);
526 break;
527 case CK_Down:
528 mcview_move_down (view, 1);
529 break;
530 case CK_HalfPageUp:
531 mcview_move_up (view, (view->data_area.height + 1) / 2);
532 break;
533 case CK_HalfPageDown:
534 mcview_move_down (view, (view->data_area.height + 1) / 2);
535 break;
536 case CK_PageUp:
537 mcview_move_up (view, view->data_area.height);
538 break;
539 case CK_PageDown:
540 mcview_move_down (view, view->data_area.height);
541 break;
542 case CK_Top:
543 mcview_moveto_top (view);
544 break;
545 case CK_Bottom:
546 mcview_moveto_bottom (view);
547 break;
548 case CK_Shell:
549 toggle_subshell ();
550 break;
551 case CK_Ruler:
552 mcview_display_toggle_ruler (view);
553 break;
554 case CK_Bookmark:
555 view->dpy_start = view->marks[view->marker];
556 view->dpy_paragraph_skip_lines = 0;
557 view->dpy_wrap_dirty = TRUE;
558 view->dirty++;
559 break;
560 case CK_BookmarkGoto:
561 view->marks[view->marker] = view->dpy_start;
562 break;
563 #ifdef HAVE_CHARSET
564 case CK_SelectCodepage:
565 mcview_select_encoding (view);
566 view->dirty++;
567 break;
568 #endif
569 case CK_FileNext:
570 case CK_FilePrev:
571
572 if (!mcview_is_in_panel (view))
573 mcview_load_next_prev (view, command == CK_FileNext ? 1 : -1);
574 break;
575 case CK_History:
576 mcview_load_file_from_history (view);
577 break;
578 case CK_Quit:
579 if (!mcview_is_in_panel (view))
580 dlg_stop (DIALOG (WIDGET (view)->owner));
581 break;
582 case CK_Cancel:
583
584 break;
585 default:
586 res = MSG_NOT_HANDLED;
587 }
588 return res;
589 }
590
591
592
593 static long
594 mcview_lookup_key (WView * view, int key)
595 {
596 if (view->mode_flags.hex)
597 return keybind_lookup_keymap_command (view->hex_keymap, key);
598
599 return widget_lookup_key (WIDGET (view), key);
600 }
601
602
603
604 static cb_ret_t
605 mcview_handle_key (WView * view, int key)
606 {
607 long command;
608
609 #ifdef HAVE_CHARSET
610 key = convert_from_input_c (key);
611 #endif
612
613 if (view->hexedit_mode && view->mode_flags.hex
614 && mcview_handle_editkey (view, key) == MSG_HANDLED)
615 return MSG_HANDLED;
616
617 command = mcview_lookup_key (view, key);
618 if (command != CK_IgnoreKey && mcview_execute_cmd (view, command) == MSG_HANDLED)
619 return MSG_HANDLED;
620
621 #ifdef MC_ENABLE_DEBUGGING_CODE
622 if (c == 't')
623 {
624 mcview_ccache_dump (view);
625 return MSG_HANDLED;
626 }
627 #endif
628 if (key >= '0' && key <= '9')
629 view->marker = key - '0';
630
631
632 return MSG_NOT_HANDLED;
633 }
634
635
636
637
638 static inline void
639 mcview_resize (WView * view)
640 {
641 view->dpy_wrap_dirty = TRUE;
642 mcview_compute_areas (view);
643 mcview_update_bytes_per_line (view);
644 }
645
646
647
648 static gboolean
649 mcview_ok_to_quit (WView * view)
650 {
651 int r;
652
653 if (view->change_list == NULL)
654 return TRUE;
655
656 if (!mc_global.midnight_shutdown)
657 {
658 query_set_sel (2);
659 r = query_dialog (_("Quit"),
660 _("File was modified. Save with exit?"), D_NORMAL, 3,
661 _("&Yes"), _("&No"), _("&Cancel quit"));
662 }
663 else
664 {
665 r = query_dialog (_("Quit"),
666 _("Midnight Commander is being shut down.\nSave modified file?"),
667 D_NORMAL, 2, _("&Yes"), _("&No"));
668
669 if (r == -1)
670 r = 1;
671 }
672
673 switch (r)
674 {
675 case 0:
676 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
677 case 1:
678 mcview_hexedit_free_change_list (view);
679 return TRUE;
680 default:
681 return FALSE;
682 }
683 }
684
685
686
687
688
689 cb_ret_t
690 mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
691 {
692 WView *view = (WView *) w;
693 cb_ret_t i;
694
695 mcview_compute_areas (view);
696 mcview_update_bytes_per_line (view);
697
698 switch (msg)
699 {
700 case MSG_INIT:
701 if (mcview_is_in_panel (view))
702 add_hook (&select_file_hook, mcview_hook, view);
703 else
704 view->dpy_bbar_dirty = TRUE;
705 return MSG_HANDLED;
706
707 case MSG_DRAW:
708 mcview_display (view);
709 return MSG_HANDLED;
710
711 case MSG_CURSOR:
712 if (view->mode_flags.hex)
713 mcview_place_cursor (view);
714 return MSG_HANDLED;
715
716 case MSG_KEY:
717 i = mcview_handle_key (view, parm);
718 mcview_update (view);
719 return i;
720
721 case MSG_ACTION:
722 i = mcview_execute_cmd (view, parm);
723 mcview_update (view);
724 return i;
725
726 case MSG_FOCUS:
727 view->dpy_bbar_dirty = TRUE;
728
729 mcview_update (view);
730 return MSG_HANDLED;
731
732 case MSG_RESIZE:
733 widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
734 mcview_resize (view);
735 return MSG_HANDLED;
736
737 case MSG_DESTROY:
738 if (mcview_is_in_panel (view))
739 {
740 delete_hook (&select_file_hook, mcview_hook);
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761 delete_hook (&idle_hook, mcview_hook);
762
763 if (mc_global.midnight_shutdown)
764 mcview_ok_to_quit (view);
765 }
766 mcview_done (view);
767 mcview_remove_ext_script (view);
768 return MSG_HANDLED;
769
770 default:
771 return widget_default_callback (w, sender, msg, parm, data);
772 }
773 }
774
775
776
777 cb_ret_t
778 mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
779 {
780 WDialog *h = DIALOG (w);
781 WView *view;
782
783 switch (msg)
784 {
785 case MSG_ACTION:
786
787
788
789
790 return mcview_execute_cmd (NULL, parm);
791
792 case MSG_VALIDATE:
793 view = (WView *) widget_find_by_type (w, mcview_callback);
794
795 widget_set_state (w, WST_ACTIVE, TRUE);
796 if (mcview_ok_to_quit (view))
797 dlg_stop (h);
798 else
799 mcview_update (view);
800 return MSG_HANDLED;
801
802 default:
803 return dlg_default_callback (w, sender, msg, parm, data);
804 }
805 }
806
807