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