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