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/keymap.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, TRUE);
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->str, 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->fname->len && strncmp (fname, fe->fname->str, 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 =
378 vfs_path_append_new (view->workdir_vpath, dir->list[*dir_idx].fname->str, (char *) NULL);
379 mcview_done (view);
380 mcview_remove_ext_script (view);
381 mcview_init (view);
382 if (regex_command_for (view, vfile, "View", &ext_script) == 0)
383 mcview_load (view, NULL, vfs_path_as_str (vfile), 0, 0, 0);
384 vfs_path_free (vfile, TRUE);
385 view->dir = dir;
386 view->dir_idx = dir_idx;
387 view->ext_script = ext_script;
388
389 view->dpy_bbar_dirty = FALSE;
390 view->dirty++;
391 }
392
393
394
395 static void
396 mcview_load_file_from_history (WView * view)
397 {
398 char *filename;
399 int action;
400
401 filename = show_file_history (CONST_WIDGET (view), &action);
402
403 if (filename != NULL && (action == CK_View || action == CK_Enter))
404 {
405 mcview_done (view);
406 mcview_init (view);
407
408 mcview_load (view, NULL, filename, 0, 0, 0);
409
410 view->dpy_bbar_dirty = FALSE;
411 view->dirty++;
412 }
413
414 g_free (filename);
415 }
416
417
418
419 static cb_ret_t
420 mcview_execute_cmd (WView * view, long command)
421 {
422 int res = MSG_HANDLED;
423
424 switch (command)
425 {
426 case CK_Help:
427 {
428 ev_help_t event_data = { NULL, "[Internal File Viewer]" };
429 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
430 }
431 break;
432 case CK_HexMode:
433
434 mcview_toggle_hex_mode (view);
435 break;
436 case CK_HexEditMode:
437
438 mcview_toggle_hexedit_mode (view);
439 break;
440 case CK_ToggleNavigation:
441 view->hexview_in_text = !view->hexview_in_text;
442 view->dirty++;
443 break;
444 case CK_LeftQuick:
445 if (!view->mode_flags.hex)
446 mcview_move_left (view, 10);
447 break;
448 case CK_RightQuick:
449 if (!view->mode_flags.hex)
450 mcview_move_right (view, 10);
451 break;
452 case CK_Goto:
453 {
454 off_t addr;
455
456 if (mcview_dialog_goto (view, &addr))
457 {
458 if (addr >= 0)
459 mcview_moveto_offset (view, addr);
460 else
461 {
462 message (D_ERROR, _("Warning"), "%s", _("Invalid value"));
463 view->dirty++;
464 }
465 }
466 break;
467 }
468 case CK_Save:
469 mcview_hexedit_save_changes (view);
470 break;
471 case CK_Search:
472 mcview_search (view, TRUE);
473 break;
474 case CK_SearchContinue:
475 mcview_continue_search_cmd (view);
476 break;
477 case CK_SearchForward:
478 mcview_search_options.backwards = FALSE;
479 mcview_search (view, TRUE);
480 break;
481 case CK_SearchForwardContinue:
482 mcview_search_options.backwards = FALSE;
483 mcview_continue_search_cmd (view);
484 break;
485 case CK_SearchBackward:
486 mcview_search_options.backwards = TRUE;
487 mcview_search (view, TRUE);
488 break;
489 case CK_SearchBackwardContinue:
490 mcview_search_options.backwards = TRUE;
491 mcview_continue_search_cmd (view);
492 break;
493 case CK_SearchOppositeContinue:
494 {
495 gboolean direction;
496
497 direction = mcview_search_options.backwards;
498 mcview_search_options.backwards = !direction;
499 mcview_continue_search_cmd (view);
500 mcview_search_options.backwards = direction;
501 }
502 break;
503 case CK_WrapMode:
504
505 mcview_toggle_wrap_mode (view);
506 break;
507 case CK_MagicMode:
508 mcview_toggle_magic_mode (view);
509 break;
510 case CK_NroffMode:
511 mcview_toggle_nroff_mode (view);
512 break;
513 case CK_Home:
514 mcview_moveto_bol (view);
515 break;
516 case CK_End:
517 mcview_moveto_eol (view);
518 break;
519 case CK_Left:
520 mcview_move_left (view, 1);
521 break;
522 case CK_Right:
523 mcview_move_right (view, 1);
524 break;
525 case CK_Up:
526 mcview_move_up (view, 1);
527 break;
528 case CK_Down:
529 mcview_move_down (view, 1);
530 break;
531 case CK_HalfPageUp:
532 mcview_move_up (view, (view->data_area.height + 1) / 2);
533 break;
534 case CK_HalfPageDown:
535 mcview_move_down (view, (view->data_area.height + 1) / 2);
536 break;
537 case CK_PageUp:
538 mcview_move_up (view, view->data_area.height);
539 break;
540 case CK_PageDown:
541 mcview_move_down (view, view->data_area.height);
542 break;
543 case CK_Top:
544 mcview_moveto_top (view);
545 break;
546 case CK_Bottom:
547 mcview_moveto_bottom (view);
548 break;
549 case CK_Shell:
550 toggle_subshell ();
551 break;
552 case CK_Ruler:
553 mcview_display_toggle_ruler (view);
554 break;
555 case CK_Bookmark:
556 view->dpy_start = view->marks[view->marker];
557 view->dpy_paragraph_skip_lines = 0;
558 view->dpy_wrap_dirty = TRUE;
559 view->dirty++;
560 break;
561 case CK_BookmarkGoto:
562 view->marks[view->marker] = view->dpy_start;
563 break;
564 #ifdef HAVE_CHARSET
565 case CK_SelectCodepage:
566 mcview_select_encoding (view);
567 view->dirty++;
568 break;
569 #endif
570 case CK_FileNext:
571 case CK_FilePrev:
572
573 if (!mcview_is_in_panel (view))
574 mcview_load_next_prev (view, command == CK_FileNext ? 1 : -1);
575 break;
576 case CK_History:
577 mcview_load_file_from_history (view);
578 break;
579 case CK_Quit:
580 if (!mcview_is_in_panel (view))
581 dlg_stop (DIALOG (WIDGET (view)->owner));
582 break;
583 case CK_Cancel:
584
585 break;
586 default:
587 res = MSG_NOT_HANDLED;
588 }
589 return res;
590 }
591
592
593
594 static long
595 mcview_lookup_key (WView * view, int key)
596 {
597 if (view->mode_flags.hex)
598 return keybind_lookup_keymap_command (view->hex_keymap, key);
599
600 return widget_lookup_key (WIDGET (view), key);
601 }
602
603
604
605 static cb_ret_t
606 mcview_handle_key (WView * view, int key)
607 {
608 long command;
609
610 #ifdef HAVE_CHARSET
611 key = convert_from_input_c (key);
612 #endif
613
614 if (view->hexedit_mode && view->mode_flags.hex
615 && mcview_handle_editkey (view, key) == MSG_HANDLED)
616 return MSG_HANDLED;
617
618 command = mcview_lookup_key (view, key);
619 if (command != CK_IgnoreKey && mcview_execute_cmd (view, command) == MSG_HANDLED)
620 return MSG_HANDLED;
621
622 #ifdef MC_ENABLE_DEBUGGING_CODE
623 if (c == 't')
624 {
625 mcview_ccache_dump (view);
626 return MSG_HANDLED;
627 }
628 #endif
629 if (key >= '0' && key <= '9')
630 view->marker = key - '0';
631
632
633 return MSG_NOT_HANDLED;
634 }
635
636
637
638
639 static inline void
640 mcview_resize (WView * view)
641 {
642 view->dpy_wrap_dirty = TRUE;
643 mcview_compute_areas (view);
644 mcview_update_bytes_per_line (view);
645 }
646
647
648
649 static gboolean
650 mcview_ok_to_quit (WView * view)
651 {
652 int r;
653
654 if (view->change_list == NULL)
655 return TRUE;
656
657 if (!mc_global.midnight_shutdown)
658 {
659 query_set_sel (2);
660 r = query_dialog (_("Quit"),
661 _("File was modified. Save with exit?"), D_NORMAL, 3,
662 _("&Yes"), _("&No"), _("&Cancel quit"));
663 }
664 else
665 {
666 r = query_dialog (_("Quit"),
667 _("Midnight Commander is being shut down.\nSave modified file?"),
668 D_NORMAL, 2, _("&Yes"), _("&No"));
669
670 if (r == -1)
671 r = 1;
672 }
673
674 switch (r)
675 {
676 case 0:
677 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
678 case 1:
679 mcview_hexedit_free_change_list (view);
680 return TRUE;
681 default:
682 return FALSE;
683 }
684 }
685
686
687
688
689
690 cb_ret_t
691 mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
692 {
693 WView *view = (WView *) w;
694 cb_ret_t i;
695
696 mcview_compute_areas (view);
697 mcview_update_bytes_per_line (view);
698
699 switch (msg)
700 {
701 case MSG_INIT:
702 if (mcview_is_in_panel (view))
703 add_hook (&select_file_hook, mcview_hook, view);
704 else
705 view->dpy_bbar_dirty = TRUE;
706 return MSG_HANDLED;
707
708 case MSG_DRAW:
709 mcview_display (view);
710 return MSG_HANDLED;
711
712 case MSG_CURSOR:
713 if (view->mode_flags.hex)
714 mcview_place_cursor (view);
715 return MSG_HANDLED;
716
717 case MSG_KEY:
718 i = mcview_handle_key (view, parm);
719 mcview_update (view);
720 return i;
721
722 case MSG_ACTION:
723 i = mcview_execute_cmd (view, parm);
724 mcview_update (view);
725 return i;
726
727 case MSG_FOCUS:
728 view->dpy_bbar_dirty = TRUE;
729
730 mcview_update (view);
731 return MSG_HANDLED;
732
733 case MSG_RESIZE:
734 widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
735 mcview_resize (view);
736 return MSG_HANDLED;
737
738 case MSG_DESTROY:
739 if (mcview_is_in_panel (view))
740 {
741 delete_hook (&select_file_hook, mcview_hook);
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762 delete_hook (&idle_hook, mcview_hook);
763
764 if (mc_global.midnight_shutdown)
765 mcview_ok_to_quit (view);
766 }
767 mcview_done (view);
768 mcview_remove_ext_script (view);
769 return MSG_HANDLED;
770
771 default:
772 return widget_default_callback (w, sender, msg, parm, data);
773 }
774 }
775
776
777
778 cb_ret_t
779 mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
780 {
781 WDialog *h = DIALOG (w);
782 WView *view;
783
784 switch (msg)
785 {
786 case MSG_ACTION:
787
788
789
790
791 return mcview_execute_cmd (NULL, parm);
792
793 case MSG_VALIDATE:
794 view = (WView *) widget_find_by_type (w, mcview_callback);
795
796 widget_set_state (w, WST_ACTIVE, TRUE);
797 if (mcview_ok_to_quit (view))
798 dlg_stop (h);
799 else
800 mcview_update (view);
801 return MSG_HANDLED;
802
803 default:
804 return dlg_default_callback (w, sender, msg, parm, data);
805 }
806 }
807
808