This source file includes following definitions.
- max
- parse_ignore_dirs
- find_load_options
- find_save_options
- add_to_list
- add_to_list_take
- stop_idle
- status_update
- found_num_update
- get_list_info
- find_check_regexp
- find_toggle_enable_ignore_dirs
- find_toggle_enable_params
- find_toggle_enable_content
- find_parm_callback
- find_parameters
- push_directory
- pop_directory
- queue_dir_free
- clear_stack
- insert_file
- find_add_match
- check_find_events
- search_content
- find_ignore_dir_search
- find_rotate_dash
- do_search
- init_find_vars
- find_do_view_edit
- view_edit_currently_selected_file
- find_calc_button_locations
- find_adjust_header
- find_relocate_buttons
- find_resize
- find_callback
- start_stop
- find_do_view_file
- find_do_edit_file
- setup_gui
- run_process
- kill_gui
- do_find
- find_cmd
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 #include <config.h>
33
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39
40 #include "lib/global.h"
41
42 #include "lib/tty/tty.h"
43 #include "lib/tty/key.h"
44 #include "lib/skin.h"
45 #include "lib/search.h"
46 #include "lib/mcconfig.h"
47 #include "lib/vfs/vfs.h"
48 #include "lib/strutil.h"
49 #include "lib/widget.h"
50 #include "lib/util.h"
51
52 #include "src/setup.h"
53 #include "src/history.h"
54
55 #include "dir.h"
56 #include "cmd.h"
57 #include "boxes.h"
58 #include "panelize.h"
59
60
61
62
63
64 #define MAX_REFRESH_INTERVAL (G_USEC_PER_SEC / 20)
65 #define MIN_REFRESH_FILE_SIZE (256 * 1024)
66
67
68
69
70 enum
71 {
72 B_STOP = B_USER + 1,
73 B_AGAIN,
74 B_PANELIZE,
75 B_TREE,
76 B_VIEW
77 };
78
79 typedef enum
80 {
81 FIND_CONT = 0,
82 FIND_SUSPEND,
83 FIND_ABORT
84 } FindProgressStatus;
85
86
87 typedef struct
88 {
89
90 gboolean file_case_sens;
91 gboolean file_pattern;
92 gboolean find_recurs;
93 gboolean follow_symlinks;
94 gboolean skip_hidden;
95 gboolean file_all_charsets;
96
97
98 gboolean content_case_sens;
99 gboolean content_regexp;
100 gboolean content_first_hit;
101 gboolean content_whole_words;
102 gboolean content_all_charsets;
103
104
105 gboolean ignore_dirs_enable;
106
107 char *ignore_dirs;
108 } find_file_options_t;
109
110 typedef struct
111 {
112 char *dir;
113 gsize start;
114 gsize end;
115 } find_match_location_t;
116
117
118
119
120 static int start_stop (WButton *button, int action);
121 static int find_do_view_file (WButton *button, int action);
122 static int find_do_edit_file (WButton *button, int action);
123
124
125
126
127 static char **find_ignore_dirs = NULL;
128
129
130 static WInput *in_start;
131 static WInput *in_name;
132 static WInput *in_with;
133 static WInput *in_ignore;
134 static WLabel *content_label;
135 static WCheck *file_case_sens_cbox;
136 static WCheck *file_pattern_cbox;
137 static WCheck *recursively_cbox;
138 static WCheck *follow_sym_cbox;
139 static WCheck *skip_hidden_cbox;
140 static WCheck *content_case_sens_cbox;
141 static WCheck *content_regexp_cbox;
142 static WCheck *content_first_hit_cbox;
143 static WCheck *content_whole_words_cbox;
144 #ifdef HAVE_CHARSET
145 static WCheck *file_all_charsets_cbox;
146 static WCheck *content_all_charsets_cbox;
147 #endif
148 static WCheck *ignore_dirs_cbox;
149
150 static gboolean running = FALSE;
151 static char *find_pattern = NULL;
152 static char *content_pattern = NULL;
153
154 static gboolean content_is_empty = TRUE;
155 static unsigned long matches;
156 static gboolean is_start = FALSE;
157 static char *old_dir = NULL;
158
159 static gint64 last_refresh;
160
161
162 static gboolean resuming;
163 static int last_line;
164 static int last_pos;
165 static off_t last_off;
166 static int last_i;
167
168 static size_t ignore_count = 0;
169
170 static WDialog *find_dlg;
171 static WLabel *status_label;
172 static WLabel *found_num_label;
173
174
175 static GQueue dir_queue = G_QUEUE_INIT;
176
177 static struct
178 {
179 int ret_cmd;
180 button_flags_t flags;
181 const char *text;
182 int len;
183 int x;
184 Widget *button;
185 bcback_fn callback;
186 } fbuts[] = {
187 { B_ENTER, DEFPUSH_BUTTON, N_ ("&Chdir"), 0, 0, NULL, NULL },
188 { B_AGAIN, NORMAL_BUTTON, N_ ("&Again"), 0, 0, NULL, NULL },
189 { B_STOP, NORMAL_BUTTON, N_ ("S&uspend"), 0, 0, NULL, start_stop },
190 { B_STOP, NORMAL_BUTTON, N_ ("Con&tinue"), 0, 0, NULL, NULL },
191 { B_CANCEL, NORMAL_BUTTON, N_ ("&Quit"), 0, 0, NULL, NULL },
192
193 { B_PANELIZE, NORMAL_BUTTON, N_ ("Pane&lize"), 0, 0, NULL, NULL },
194 { B_VIEW, NORMAL_BUTTON, N_ ("&View - F3"), 0, 0, NULL, find_do_view_file },
195 { B_VIEW, NORMAL_BUTTON, N_ ("&Edit - F4"), 0, 0, NULL, find_do_edit_file },
196 };
197
198 static const size_t fbuts_num = G_N_ELEMENTS (fbuts);
199 static const size_t quit_button = 4;
200
201 static WListbox *find_list;
202
203 static find_file_options_t options = {
204 TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL,
205 };
206
207 static char *in_start_dir = INPUT_LAST_TEXT;
208
209 static mc_search_t *search_file_handle = NULL;
210 static mc_search_t *search_content_handle = NULL;
211
212
213
214
215
216
217 #undef max
218
219 static int
220 max (int a, int b)
221 {
222 return (a > b ? a : b);
223 }
224
225
226
227 static void
228 parse_ignore_dirs (const char *ignore_dirs)
229 {
230 size_t r = 0, w = 0;
231
232 if (!options.ignore_dirs_enable || ignore_dirs == NULL || ignore_dirs[0] == '\0')
233 return;
234
235 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
236
237
238
239 for (; find_ignore_dirs[r] != NULL; r++)
240 {
241 if (find_ignore_dirs[r][0] == '\0')
242 {
243
244 MC_PTR_FREE (find_ignore_dirs[r]);
245 continue;
246 }
247
248 if (r != w)
249 {
250
251 find_ignore_dirs[w] = find_ignore_dirs[r];
252 find_ignore_dirs[r] = NULL;
253 }
254
255 canonicalize_pathname (find_ignore_dirs[w]);
256 if (find_ignore_dirs[w][0] != '\0')
257 w++;
258 else
259 MC_PTR_FREE (find_ignore_dirs[w]);
260 }
261
262 if (find_ignore_dirs[0] == NULL)
263 {
264 g_strfreev (find_ignore_dirs);
265 find_ignore_dirs = NULL;
266 }
267 }
268
269
270
271 static void
272 find_load_options (void)
273 {
274 static gboolean loaded = FALSE;
275
276 if (loaded)
277 return;
278
279 loaded = TRUE;
280
281 options.file_case_sens =
282 mc_config_get_bool (mc_global.main_config, "FindFile", "file_case_sens", TRUE);
283 options.file_pattern =
284 mc_config_get_bool (mc_global.main_config, "FindFile", "file_shell_pattern", TRUE);
285 options.find_recurs =
286 mc_config_get_bool (mc_global.main_config, "FindFile", "file_find_recurs", TRUE);
287 options.follow_symlinks =
288 mc_config_get_bool (mc_global.main_config, "FindFile", "follow_symlinks", FALSE);
289 options.skip_hidden =
290 mc_config_get_bool (mc_global.main_config, "FindFile", "file_skip_hidden", FALSE);
291 options.file_all_charsets =
292 mc_config_get_bool (mc_global.main_config, "FindFile", "file_all_charsets", FALSE);
293 options.content_case_sens =
294 mc_config_get_bool (mc_global.main_config, "FindFile", "content_case_sens", TRUE);
295 options.content_regexp =
296 mc_config_get_bool (mc_global.main_config, "FindFile", "content_regexp", FALSE);
297 options.content_first_hit =
298 mc_config_get_bool (mc_global.main_config, "FindFile", "content_first_hit", FALSE);
299 options.content_whole_words =
300 mc_config_get_bool (mc_global.main_config, "FindFile", "content_whole_words", FALSE);
301 options.content_all_charsets =
302 mc_config_get_bool (mc_global.main_config, "FindFile", "content_all_charsets", FALSE);
303 options.ignore_dirs_enable =
304 mc_config_get_bool (mc_global.main_config, "FindFile", "ignore_dirs_enable", TRUE);
305 options.ignore_dirs =
306 mc_config_get_string (mc_global.main_config, "FindFile", "ignore_dirs", "");
307
308 if (options.ignore_dirs[0] == '\0')
309 MC_PTR_FREE (options.ignore_dirs);
310 }
311
312
313
314 static void
315 find_save_options (void)
316 {
317 mc_config_set_bool (mc_global.main_config, "FindFile", "file_case_sens",
318 options.file_case_sens);
319 mc_config_set_bool (mc_global.main_config, "FindFile", "file_shell_pattern",
320 options.file_pattern);
321 mc_config_set_bool (mc_global.main_config, "FindFile", "file_find_recurs", options.find_recurs);
322 mc_config_set_bool (mc_global.main_config, "FindFile", "follow_symlinks",
323 options.follow_symlinks);
324 mc_config_set_bool (mc_global.main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
325 mc_config_set_bool (mc_global.main_config, "FindFile", "file_all_charsets",
326 options.file_all_charsets);
327 mc_config_set_bool (mc_global.main_config, "FindFile", "content_case_sens",
328 options.content_case_sens);
329 mc_config_set_bool (mc_global.main_config, "FindFile", "content_regexp",
330 options.content_regexp);
331 mc_config_set_bool (mc_global.main_config, "FindFile", "content_first_hit",
332 options.content_first_hit);
333 mc_config_set_bool (mc_global.main_config, "FindFile", "content_whole_words",
334 options.content_whole_words);
335 mc_config_set_bool (mc_global.main_config, "FindFile", "content_all_charsets",
336 options.content_all_charsets);
337 mc_config_set_bool (mc_global.main_config, "FindFile", "ignore_dirs_enable",
338 options.ignore_dirs_enable);
339 mc_config_set_string (mc_global.main_config, "FindFile", "ignore_dirs", options.ignore_dirs);
340 }
341
342
343
344 static inline char *
345 add_to_list (const char *text, void *data)
346 {
347 return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data, TRUE);
348 }
349
350
351
352 static inline char *
353 add_to_list_take (char *text, void *data)
354 {
355 return listbox_add_item_take (find_list, LISTBOX_APPEND_AT_END, 0, text, data, TRUE);
356 }
357
358
359
360 static inline void
361 stop_idle (void *data)
362 {
363 widget_idle (WIDGET (data), FALSE);
364 }
365
366
367
368 static inline void
369 status_update (const char *text)
370 {
371 label_set_text (status_label, text);
372 }
373
374
375
376 static inline void
377 found_num_update (void)
378 {
379 label_set_textv (found_num_label, _ ("Found: %lu"), matches);
380 }
381
382
383
384 static void
385 get_list_info (char **file, char **dir, gsize *start, gsize *end)
386 {
387 find_match_location_t *location;
388
389 listbox_get_current (find_list, file, (void **) &location);
390 if (location != NULL)
391 {
392 if (dir != NULL)
393 *dir = location->dir;
394 if (start != NULL)
395 *start = location->start;
396 if (end != NULL)
397 *end = location->end;
398 }
399 else
400 {
401 if (dir != NULL)
402 *dir = NULL;
403 }
404 }
405
406
407
408
409 static gboolean
410 find_check_regexp (const char *r)
411 {
412 mc_search_t *search;
413 gboolean regexp_ok = FALSE;
414
415 search = mc_search_new (r, NULL);
416
417 if (search != NULL)
418 {
419 search->search_type = MC_SEARCH_T_REGEX;
420 regexp_ok = mc_search_prepare (search);
421 mc_search_free (search);
422 }
423
424 return regexp_ok;
425 }
426
427
428
429 static void
430 find_toggle_enable_ignore_dirs (void)
431 {
432 widget_disable (WIDGET (in_ignore), !ignore_dirs_cbox->state);
433 }
434
435
436
437 static void
438 find_toggle_enable_params (void)
439 {
440 gboolean disable = input_is_empty (in_name);
441
442 widget_disable (WIDGET (file_pattern_cbox), disable);
443 widget_disable (WIDGET (file_case_sens_cbox), disable);
444 #ifdef HAVE_CHARSET
445 widget_disable (WIDGET (file_all_charsets_cbox), disable);
446 #endif
447 }
448
449
450
451 static void
452 find_toggle_enable_content (void)
453 {
454 widget_disable (WIDGET (content_regexp_cbox), content_is_empty);
455 widget_disable (WIDGET (content_case_sens_cbox), content_is_empty);
456 #ifdef HAVE_CHARSET
457 widget_disable (WIDGET (content_all_charsets_cbox), content_is_empty);
458 #endif
459 widget_disable (WIDGET (content_whole_words_cbox), content_is_empty);
460 widget_disable (WIDGET (content_first_hit_cbox), content_is_empty);
461 }
462
463
464
465
466
467
468
469 static cb_ret_t
470 find_parm_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
471 {
472
473
474
475
476
477
478
479
480
481
482 static gboolean first_draw = TRUE;
483
484 WDialog *h = DIALOG (w);
485
486 switch (msg)
487 {
488 case MSG_INIT:
489 group_default_callback (w, NULL, MSG_INIT, 0, NULL);
490 first_draw = TRUE;
491 return MSG_HANDLED;
492
493 case MSG_NOTIFY:
494 if (sender == WIDGET (ignore_dirs_cbox))
495 {
496 find_toggle_enable_ignore_dirs ();
497 return MSG_HANDLED;
498 }
499
500 return MSG_NOT_HANDLED;
501
502 case MSG_VALIDATE:
503 if (h->ret_value != B_ENTER)
504 return MSG_HANDLED;
505
506
507 if (!file_pattern_cbox->state && !input_is_empty (in_name)
508 && !find_check_regexp (input_get_ctext (in_name)))
509 {
510
511 widget_set_state (w, WST_ACTIVE, TRUE);
512 message (D_ERROR, MSG_ERROR, _ ("Malformed regular expression"));
513 widget_select (WIDGET (in_name));
514 return MSG_HANDLED;
515 }
516
517
518 if (content_regexp_cbox->state && !content_is_empty
519 && !find_check_regexp (input_get_ctext (in_with)))
520 {
521
522 widget_set_state (w, WST_ACTIVE, TRUE);
523 message (D_ERROR, MSG_ERROR, _ ("Malformed regular expression"));
524 widget_select (WIDGET (in_with));
525 return MSG_HANDLED;
526 }
527
528 return MSG_HANDLED;
529
530 case MSG_POST_KEY:
531 if (GROUP (h)->current->data == in_name)
532 find_toggle_enable_params ();
533 else if (GROUP (h)->current->data == in_with)
534 {
535 content_is_empty = input_is_empty (in_with);
536 find_toggle_enable_content ();
537 }
538 return MSG_HANDLED;
539
540 case MSG_DRAW:
541 if (first_draw)
542 {
543 find_toggle_enable_ignore_dirs ();
544 find_toggle_enable_params ();
545 find_toggle_enable_content ();
546 }
547
548 first_draw = FALSE;
549 MC_FALLTHROUGH;
550
551 default:
552 return dlg_default_callback (w, sender, msg, parm, data);
553 }
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569 static gboolean
570 find_parameters (WPanel *panel, char **start_dir, ssize_t *start_dir_len, char **ignore_dirs,
571 char **pattern, char **content)
572 {
573 WGroup *g;
574
575
576 #ifdef HAVE_CHARSET
577 const int lines = 19;
578 #else
579 const int lines = 18;
580 #endif
581 int cols = 68;
582
583 gboolean return_value;
584
585
586 const char *file_name_label = N_ ("File name:");
587 const char *file_recurs_label = N_ ("&Find recursively");
588 const char *file_follow_symlinks = N_ ("Follow s&ymlinks");
589 const char *file_pattern_label = N_ ("&Using shell patterns");
590 #ifdef HAVE_CHARSET
591 const char *file_all_charsets_label = N_ ("&All charsets");
592 #endif
593 const char *file_case_label = N_ ("Cas&e sensitive");
594 const char *file_skip_hidden_label = N_ ("S&kip hidden");
595
596
597 const char *content_content_label = N_ ("Content:");
598 const char *content_use_label = N_ ("Sea&rch for content");
599 const char *content_regexp_label = N_ ("Re&gular expression");
600 const char *content_case_label = N_ ("Case sens&itive");
601 #ifdef HAVE_CHARSET
602 const char *content_all_charsets_label = N_ ("A&ll charsets");
603 #endif
604 const char *content_whole_words_label = N_ ("&Whole words");
605 const char *content_first_hit_label = N_ ("Fir&st hit");
606
607 const char *buts[] = {
608 N_ ("&Tree"),
609 N_ ("&OK"),
610 N_ ("&Cancel"),
611 };
612
613
614 int b0, b1, b2, b12;
615 int y1, y2, x1, x2;
616
617 int cw;
618
619 #ifdef ENABLE_NLS
620 {
621 size_t i;
622
623 file_name_label = _ (file_name_label);
624 file_recurs_label = _ (file_recurs_label);
625 file_follow_symlinks = _ (file_follow_symlinks);
626 file_pattern_label = _ (file_pattern_label);
627 # ifdef HAVE_CHARSET
628 file_all_charsets_label = _ (file_all_charsets_label);
629 # endif
630 file_case_label = _ (file_case_label);
631 file_skip_hidden_label = _ (file_skip_hidden_label);
632
633
634 content_content_label = _ (content_content_label);
635 content_use_label = _ (content_use_label);
636 content_regexp_label = _ (content_regexp_label);
637 content_case_label = _ (content_case_label);
638 # ifdef HAVE_CHARSET
639 content_all_charsets_label = _ (content_all_charsets_label);
640 # endif
641 content_whole_words_label = _ (content_whole_words_label);
642 content_first_hit_label = _ (content_first_hit_label);
643
644 for (i = 0; i < G_N_ELEMENTS (buts); i++)
645 buts[i] = _ (buts[i]);
646 }
647 #endif
648
649
650
651
652 cw = str_term_width1 (file_name_label);
653 cw = max (cw, str_term_width1 (file_recurs_label) + 4);
654 cw = max (cw, str_term_width1 (file_follow_symlinks) + 4);
655 cw = max (cw, str_term_width1 (file_pattern_label) + 4);
656 #ifdef HAVE_CHARSET
657 cw = max (cw, str_term_width1 (file_all_charsets_label) + 4);
658 #endif
659 cw = max (cw, str_term_width1 (file_case_label) + 4);
660 cw = max (cw, str_term_width1 (file_skip_hidden_label) + 4);
661
662 cw = max (cw, str_term_width1 (content_content_label) + 4);
663 cw = max (cw, str_term_width1 (content_use_label) + 4);
664 cw = max (cw, str_term_width1 (content_regexp_label) + 4);
665 cw = max (cw, str_term_width1 (content_case_label) + 4);
666 #ifdef HAVE_CHARSET
667 cw = max (cw, str_term_width1 (content_all_charsets_label) + 4);
668 #endif
669 cw = max (cw, str_term_width1 (content_whole_words_label) + 4);
670 cw = max (cw, str_term_width1 (content_first_hit_label) + 4);
671
672
673 b0 = str_term_width1 (buts[0]) + 3;
674 b1 = str_term_width1 (buts[1]) + 5;
675 b2 = str_term_width1 (buts[2]) + 3;
676 b12 = b1 + b2 + 1;
677
678 cols = max (cols, max (b12, cw * 2 + 1) + 6);
679
680 find_load_options ();
681
682 if (in_start_dir == NULL)
683 in_start_dir = g_strdup (".");
684
685 find_dlg = dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors,
686 find_parm_callback, NULL, "[Find File]", _ ("Find File"));
687 g = GROUP (find_dlg);
688
689 x1 = 3;
690 x2 = cols / 2 + 1;
691 cw = (cols - 7) / 2;
692 y1 = 2;
693
694 group_add_widget (g, label_new (y1++, x1, _ ("Start at:")));
695 in_start = input_new (y1, x1, input_colors, cols - b0 - 7, in_start_dir, "start",
696 INPUT_COMPLETE_CD | INPUT_COMPLETE_FILENAMES);
697 group_add_widget (g, in_start);
698
699 group_add_widget (g, button_new (y1++, cols - b0 - 3, B_TREE, NORMAL_BUTTON, buts[0], NULL));
700
701 ignore_dirs_cbox =
702 check_new (y1++, x1, options.ignore_dirs_enable, _ ("Ena&ble ignore directories:"));
703 group_add_widget (g, ignore_dirs_cbox);
704
705 in_ignore = input_new (y1++, x1, input_colors, cols - 6,
706 options.ignore_dirs != NULL ? options.ignore_dirs : "", "ignoredirs",
707 INPUT_COMPLETE_CD | INPUT_COMPLETE_FILENAMES);
708 group_add_widget (g, in_ignore);
709
710 group_add_widget (g, hline_new (y1++, -1, -1));
711
712 y2 = y1;
713
714
715 group_add_widget (g, label_new (y1++, x1, file_name_label));
716 in_name = input_new (y1++, x1, input_colors, cw, INPUT_LAST_TEXT, "name",
717 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
718 group_add_widget (g, in_name);
719
720
721 content_label = label_new (y2++, x2, content_content_label);
722 group_add_widget (g, content_label);
723 in_with = input_new (y2++, x2, input_colors, cw, content_is_empty ? "" : INPUT_LAST_TEXT,
724 MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_NONE);
725 in_with->label = content_label;
726 group_add_widget (g, in_with);
727
728
729 recursively_cbox = check_new (y1++, x1, options.find_recurs, file_recurs_label);
730 group_add_widget (g, recursively_cbox);
731
732 follow_sym_cbox = check_new (y1++, x1, options.follow_symlinks, file_follow_symlinks);
733 group_add_widget (g, follow_sym_cbox);
734
735 file_pattern_cbox = check_new (y1++, x1, options.file_pattern, file_pattern_label);
736 group_add_widget (g, file_pattern_cbox);
737
738 file_case_sens_cbox = check_new (y1++, x1, options.file_case_sens, file_case_label);
739 group_add_widget (g, file_case_sens_cbox);
740
741 #ifdef HAVE_CHARSET
742 file_all_charsets_cbox =
743 check_new (y1++, x1, options.file_all_charsets, file_all_charsets_label);
744 group_add_widget (g, file_all_charsets_cbox);
745 #endif
746
747 skip_hidden_cbox = check_new (y1++, x1, options.skip_hidden, file_skip_hidden_label);
748 group_add_widget (g, skip_hidden_cbox);
749
750
751 content_whole_words_cbox =
752 check_new (y2++, x2, options.content_whole_words, content_whole_words_label);
753 group_add_widget (g, content_whole_words_cbox);
754
755 content_regexp_cbox = check_new (y2++, x2, options.content_regexp, content_regexp_label);
756 group_add_widget (g, content_regexp_cbox);
757
758 content_case_sens_cbox = check_new (y2++, x2, options.content_case_sens, content_case_label);
759 group_add_widget (g, content_case_sens_cbox);
760
761 #ifdef HAVE_CHARSET
762 content_all_charsets_cbox =
763 check_new (y2++, x2, options.content_all_charsets, content_all_charsets_label);
764 group_add_widget (g, content_all_charsets_cbox);
765 #endif
766
767 content_first_hit_cbox =
768 check_new (y2++, x2, options.content_first_hit, content_first_hit_label);
769 group_add_widget (g, content_first_hit_cbox);
770
771
772 y1 = max (y1, y2);
773 x1 = (cols - b12) / 2;
774 group_add_widget (g, hline_new (y1++, -1, -1));
775 group_add_widget (g, button_new (y1, x1, B_ENTER, DEFPUSH_BUTTON, buts[1], NULL));
776 group_add_widget (g, button_new (y1, x1 + b1 + 1, B_CANCEL, NORMAL_BUTTON, buts[2], NULL));
777
778 find_par_start:
779 widget_select (WIDGET (in_name));
780
781 switch (dlg_run (find_dlg))
782 {
783 case B_CANCEL:
784 return_value = FALSE;
785 break;
786
787 case B_TREE:
788 {
789 const char *start_cstr;
790 const char *temp_dir;
791
792 start_cstr = input_get_ctext (in_start);
793
794 if (input_is_empty (in_start) || DIR_IS_DOT (start_cstr))
795 temp_dir = vfs_path_as_str (panel->cwd_vpath);
796 else
797 temp_dir = start_cstr;
798
799 if (in_start_dir != INPUT_LAST_TEXT)
800 g_free (in_start_dir);
801 in_start_dir = tree_box (temp_dir);
802 if (in_start_dir == NULL)
803 in_start_dir = g_strdup (temp_dir);
804
805 input_assign_text (in_start, in_start_dir);
806
807
808 goto find_par_start;
809 }
810
811 default:
812 {
813 char *s;
814
815 #ifdef HAVE_CHARSET
816 options.file_all_charsets = file_all_charsets_cbox->state;
817 options.content_all_charsets = content_all_charsets_cbox->state;
818 #endif
819 options.content_case_sens = content_case_sens_cbox->state;
820 options.content_regexp = content_regexp_cbox->state;
821 options.content_first_hit = content_first_hit_cbox->state;
822 options.content_whole_words = content_whole_words_cbox->state;
823 options.find_recurs = recursively_cbox->state;
824 options.follow_symlinks = follow_sym_cbox->state;
825 options.file_pattern = file_pattern_cbox->state;
826 options.file_case_sens = file_case_sens_cbox->state;
827 options.skip_hidden = skip_hidden_cbox->state;
828 options.ignore_dirs_enable = ignore_dirs_cbox->state;
829 g_free (options.ignore_dirs);
830 options.ignore_dirs = input_get_text (in_ignore);
831
832 *content = !input_is_empty (in_with) ? input_get_text (in_with) : NULL;
833 if (input_is_empty (in_name))
834 *pattern = g_strdup (options.file_pattern ? "*" : ".*");
835 else
836 *pattern = input_get_text (in_name);
837 *start_dir = (char *) (!input_is_empty (in_start) ? input_get_ctext (in_start) : ".");
838 if (in_start_dir != INPUT_LAST_TEXT)
839 g_free (in_start_dir);
840 in_start_dir = g_strdup (*start_dir);
841
842 s = tilde_expand (*start_dir);
843 canonicalize_pathname (s);
844
845 if (DIR_IS_DOT (s))
846 {
847 *start_dir = g_strdup (vfs_path_as_str (panel->cwd_vpath));
848
849
850 *start_dir_len = (ssize_t) strlen (*start_dir);
851 g_free (s);
852 }
853 else if (g_path_is_absolute (s))
854 {
855 *start_dir = s;
856 *start_dir_len = -1;
857 }
858 else
859 {
860
861 *start_dir = mc_build_filename (vfs_path_as_str (panel->cwd_vpath), s, (char *) NULL);
862 *start_dir_len = (ssize_t) vfs_path_len (panel->cwd_vpath);
863 g_free (s);
864 }
865
866 if (!options.ignore_dirs_enable || input_is_empty (in_ignore)
867 || DIR_IS_DOT (input_get_ctext (in_ignore)))
868 *ignore_dirs = NULL;
869 else
870 *ignore_dirs = input_get_text (in_ignore);
871
872 find_save_options ();
873
874 return_value = TRUE;
875 }
876 }
877
878 widget_destroy (WIDGET (find_dlg));
879
880 return return_value;
881 }
882
883
884
885 static inline void
886 push_directory (vfs_path_t *dir)
887 {
888 g_queue_push_head (&dir_queue, (void *) dir);
889 }
890
891
892
893 static inline vfs_path_t *
894 pop_directory (void)
895 {
896 return (vfs_path_t *) g_queue_pop_head (&dir_queue);
897 }
898
899
900
901 static void
902 queue_dir_free (gpointer data)
903 {
904 vfs_path_free ((vfs_path_t *) data, TRUE);
905 }
906
907
908
909
910 static void
911 clear_stack (void)
912 {
913 g_queue_clear_full (&dir_queue, queue_dir_free);
914 }
915
916
917
918 static void
919 insert_file (const char *dir, const char *file, gsize start, gsize end)
920 {
921 char *tmp_name;
922 static char *dirname = NULL;
923 find_match_location_t *location;
924
925 while (IS_PATH_SEP (dir[0]) && IS_PATH_SEP (dir[1]))
926 dir++;
927
928 if (old_dir != NULL)
929 {
930 if (strcmp (old_dir, dir) != 0)
931 {
932 g_free (old_dir);
933 old_dir = g_strdup (dir);
934 dirname = add_to_list (dir, NULL);
935 }
936 }
937 else
938 {
939 old_dir = g_strdup (dir);
940 dirname = add_to_list (dir, NULL);
941 }
942
943 tmp_name = g_strdup_printf (" %s", file);
944 location = g_malloc (sizeof (*location));
945 location->dir = dirname;
946 location->start = start;
947 location->end = end;
948 add_to_list_take (tmp_name, location);
949 }
950
951
952
953 static void
954 find_add_match (const char *dir, const char *file, gsize start, gsize end)
955 {
956 insert_file (dir, file, start, end);
957
958
959 if (matches == 0)
960 listbox_select_first (find_list);
961 widget_draw (WIDGET (find_list));
962
963 matches++;
964 found_num_update ();
965 }
966
967
968
969 static FindProgressStatus
970 check_find_events (WDialog *h)
971 {
972 Gpm_Event event;
973 int c;
974
975 event.x = -1;
976 c = tty_get_event (&event, GROUP (h)->mouse_status == MOU_REPEAT, FALSE);
977 if (c != EV_NONE)
978 {
979 dlg_process_event (h, c, &event);
980 if (h->ret_value == B_ENTER || h->ret_value == B_CANCEL || h->ret_value == B_AGAIN
981 || h->ret_value == B_PANELIZE)
982 {
983
984 return FIND_ABORT;
985 }
986 if (!widget_get_state (WIDGET (h), WST_IDLE))
987 {
988
989 return FIND_SUSPEND;
990 }
991 }
992
993 return FIND_CONT;
994 }
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007 static gboolean
1008 search_content (WDialog *h, const char *directory, const char *filename)
1009 {
1010 struct stat s;
1011 char buffer[BUF_4K] = "";
1012 int file_fd = -1;
1013 gboolean ret_val = FALSE;
1014 vfs_path_t *vpath;
1015 gint64 tv;
1016 gboolean status_updated = FALSE;
1017
1018 vpath = vfs_path_build_filename (directory, filename, (char *) NULL);
1019
1020 if (mc_stat (vpath, &s) == 0 && S_ISREG (s.st_mode))
1021 file_fd = mc_open (vpath, O_RDONLY);
1022
1023 vfs_path_free (vpath, TRUE);
1024
1025 if (file_fd == -1)
1026 return FALSE;
1027
1028
1029 tv = g_get_monotonic_time ();
1030
1031 if (s.st_size >= MIN_REFRESH_FILE_SIZE || (tv - last_refresh) > MAX_REFRESH_INTERVAL)
1032 {
1033 g_snprintf (buffer, sizeof (buffer), _ ("Grepping in %s"), filename);
1034 status_update (str_trunc (buffer, WIDGET (h)->rect.cols - 8));
1035 mc_refresh ();
1036 last_refresh = tv;
1037 status_updated = TRUE;
1038 }
1039
1040 tty_enable_interrupt_key ();
1041 tty_got_interrupt ();
1042
1043 {
1044 int line = 1;
1045 int pos = 0;
1046 int n_read = 0;
1047 off_t off = 0;
1048 gboolean found = FALSE;
1049 char *strbuf = NULL;
1050 int strbuf_size = 0;
1051 int i = -1;
1052
1053 if (resuming)
1054 {
1055
1056 resuming = FALSE;
1057 line = last_line;
1058 pos = last_pos;
1059 off = last_off;
1060 i = last_i;
1061 }
1062
1063 while (!ret_val)
1064 {
1065 char ch = '\0';
1066 gsize found_len;
1067
1068 off += i + 1;
1069 i = 0;
1070
1071
1072 while (TRUE)
1073 {
1074 if (pos >= n_read)
1075 {
1076 pos = 0;
1077 n_read = mc_read (file_fd, buffer, sizeof (buffer));
1078 if (n_read <= 0)
1079 break;
1080 }
1081
1082 ch = buffer[pos++];
1083 if (ch == '\0')
1084 {
1085
1086 if (i == 0)
1087 {
1088 off++;
1089 continue;
1090 }
1091 break;
1092 }
1093
1094 if (i >= strbuf_size - 1)
1095 {
1096 strbuf_size += 128;
1097 strbuf = g_realloc (strbuf, strbuf_size);
1098 }
1099
1100
1101 if (ch == '\n')
1102 break;
1103
1104 strbuf[i++] = ch;
1105 }
1106
1107 if (i == 0)
1108 {
1109 if (ch == '\0')
1110 break;
1111
1112
1113 goto skip_search;
1114 }
1115
1116 strbuf[i] = '\0';
1117
1118 if (!found
1119 && mc_search_run (search_content_handle, (const void *) strbuf, 0, i, &found_len))
1120 {
1121 gsize found_start;
1122 char result[BUF_MEDIUM];
1123
1124 if (!status_updated)
1125 {
1126
1127
1128 g_snprintf (result, sizeof (result), _ ("Grepping in %s"), filename);
1129 status_update (str_trunc (result, WIDGET (h)->rect.cols - 8));
1130 mc_refresh ();
1131 last_refresh = tv;
1132 status_updated = TRUE;
1133 }
1134
1135 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
1136 found_start =
1137 off + search_content_handle->normal_offset + 1;
1138 find_add_match (directory, result, found_start, found_start + found_len);
1139 found = TRUE;
1140 }
1141
1142 if (found && options.content_first_hit)
1143 break;
1144
1145 if (ch == '\n')
1146 {
1147 skip_search:
1148 found = FALSE;
1149 line++;
1150 }
1151
1152 if ((line & 0xff) == 0)
1153 {
1154 FindProgressStatus res;
1155
1156 res = check_find_events (h);
1157 switch (res)
1158 {
1159 case FIND_ABORT:
1160 stop_idle (h);
1161 ret_val = TRUE;
1162 break;
1163 case FIND_SUSPEND:
1164 resuming = TRUE;
1165 last_line = line;
1166 last_pos = pos;
1167 last_off = off;
1168 last_i = i;
1169 ret_val = TRUE;
1170 break;
1171 default:
1172 break;
1173 }
1174 }
1175 }
1176
1177 g_free (strbuf);
1178 }
1179
1180 tty_disable_interrupt_key ();
1181 mc_close (file_fd);
1182 return ret_val;
1183 }
1184
1185
1186
1187
1188
1189
1190
1191 static gboolean
1192 find_ignore_dir_search (const char *dir, size_t len)
1193 {
1194 if (find_ignore_dirs != NULL)
1195 {
1196 const size_t dlen = len == (size_t) (-1) ? strlen (dir) : len;
1197 const unsigned char dabs = g_path_is_absolute (dir) ? 1 : 0;
1198
1199 char **ignore_dir;
1200
1201 for (ignore_dir = find_ignore_dirs; *ignore_dir != NULL; ignore_dir++)
1202 {
1203 const size_t ilen = strlen (*ignore_dir);
1204 const unsigned char iabs = g_path_is_absolute (*ignore_dir) ? 2 : 0;
1205
1206
1207 if (dlen < ilen)
1208 continue;
1209
1210
1211 switch (iabs | dabs)
1212 {
1213 case 0:
1214 case 3:
1215
1216 if (strncmp (dir, *ignore_dir, ilen) == 0)
1217 {
1218
1219
1220 if (dir[ilen] == '\0' || IS_PATH_SEP (dir[ilen]))
1221 return TRUE;
1222 }
1223 break;
1224 case 1:
1225 {
1226 char *d;
1227
1228 d = strstr (dir, *ignore_dir);
1229 if (d != NULL && IS_PATH_SEP (d[-1]) && (d[ilen] == '\0' || IS_PATH_SEP (d[ilen])))
1230 return TRUE;
1231 }
1232 break;
1233 case 2:
1234
1235 break;
1236 default:
1237 return FALSE;
1238 }
1239 }
1240 }
1241
1242 return FALSE;
1243 }
1244
1245
1246
1247 static void
1248 find_rotate_dash (const WDialog *h, gboolean show)
1249 {
1250 static size_t pos = 0;
1251 static const char rotating_dash[4] = "|/-\\";
1252 const Widget *w = CONST_WIDGET (h);
1253 const int *colors;
1254
1255 colors = widget_get_colors (w);
1256 tty_setcolor (colors[DLG_COLOR_NORMAL]);
1257 widget_gotoyx (h, w->rect.lines - 7, w->rect.cols - 4);
1258 tty_print_char (show ? rotating_dash[pos] : ' ');
1259 pos = (pos + 1) % sizeof (rotating_dash);
1260 mc_refresh ();
1261 }
1262
1263
1264
1265 static int
1266 do_search (WDialog *h)
1267 {
1268 static struct vfs_dirent *dp = NULL;
1269 static DIR *dirp = NULL;
1270 static char *directory = NULL;
1271 static gboolean pop_start_dir = TRUE;
1272 struct stat tmp_stat;
1273 gsize bytes_found;
1274 unsigned short count;
1275
1276 if (h == NULL)
1277 {
1278 if (dirp != NULL)
1279 {
1280 mc_closedir (dirp);
1281 dirp = NULL;
1282 }
1283 MC_PTR_FREE (directory);
1284 dp = NULL;
1285 pop_start_dir = TRUE;
1286 return 1;
1287 }
1288
1289 for (count = 0; count < 32; count++)
1290 {
1291 while (dp == NULL)
1292 {
1293 if (dirp != NULL)
1294 {
1295 mc_closedir (dirp);
1296 dirp = NULL;
1297 }
1298
1299 while (dirp == NULL)
1300 {
1301 vfs_path_t *tmp_vpath = NULL;
1302
1303 tty_setcolor (REVERSE_COLOR);
1304
1305 while (TRUE)
1306 {
1307 tmp_vpath = pop_directory ();
1308 if (tmp_vpath == NULL)
1309 {
1310 running = FALSE;
1311 if (ignore_count == 0)
1312 status_update (_ ("Finished"));
1313 else
1314 {
1315 char msg[BUF_SMALL];
1316
1317 g_snprintf (msg, sizeof (msg),
1318 ngettext ("Finished (ignored %zu directory)",
1319 "Finished (ignored %zu directories)",
1320 ignore_count),
1321 ignore_count);
1322 status_update (msg);
1323 }
1324 if (verbose)
1325 find_rotate_dash (h, FALSE);
1326 stop_idle (h);
1327 return 0;
1328 }
1329
1330
1331
1332 if (pop_start_dir)
1333 {
1334 pop_start_dir = FALSE;
1335 break;
1336 }
1337
1338 pop_start_dir = FALSE;
1339
1340
1341 if (!find_ignore_dir_search (vfs_path_as_str (tmp_vpath), -1))
1342 break;
1343
1344 vfs_path_free (tmp_vpath, TRUE);
1345 ignore_count++;
1346 }
1347
1348 g_free (directory);
1349
1350 if (verbose)
1351 {
1352 char buffer[BUF_MEDIUM];
1353
1354 directory = (char *) vfs_path_as_str (tmp_vpath);
1355 g_snprintf (buffer, sizeof (buffer), _ ("Searching %s"), directory);
1356 status_update (str_trunc (directory, WIDGET (h)->rect.cols - 8));
1357 }
1358
1359 dirp = mc_opendir (tmp_vpath);
1360 directory = vfs_path_free (tmp_vpath, FALSE);
1361 }
1362
1363
1364 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1365 ;
1366 }
1367
1368 if (DIR_IS_DOT (dp->d_name) || DIR_IS_DOTDOT (dp->d_name))
1369 {
1370
1371 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1372 ;
1373
1374 return 1;
1375 }
1376
1377 if (!(options.skip_hidden && (dp->d_name[0] == '.')))
1378 {
1379 gboolean search_ok;
1380
1381 if (options.find_recurs && (directory != NULL))
1382 {
1383
1384 if (options.ignore_dirs_enable && find_ignore_dir_search (dp->d_name, dp->d_len))
1385 ignore_count++;
1386 else
1387 {
1388 vfs_path_t *tmp_vpath;
1389 int stat_res;
1390
1391 tmp_vpath = vfs_path_build_filename (directory, dp->d_name, (char *) NULL);
1392
1393 if (options.follow_symlinks)
1394 stat_res = mc_stat (tmp_vpath, &tmp_stat);
1395 else
1396 stat_res = mc_lstat (tmp_vpath, &tmp_stat);
1397
1398 if (stat_res == 0 && S_ISDIR (tmp_stat.st_mode))
1399 push_directory (tmp_vpath);
1400 else
1401 vfs_path_free (tmp_vpath, TRUE);
1402 }
1403 }
1404
1405 search_ok = mc_search_run (search_file_handle, dp->d_name, 0, dp->d_len, &bytes_found);
1406
1407 if (search_ok)
1408 {
1409 if (content_pattern == NULL)
1410 find_add_match (directory, dp->d_name, 0, 0);
1411 else if (search_content (h, directory, dp->d_name))
1412 return 1;
1413 }
1414 }
1415
1416
1417 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1418 ;
1419 }
1420
1421 if (verbose)
1422 find_rotate_dash (h, TRUE);
1423
1424 return 1;
1425 }
1426
1427
1428
1429 static void
1430 init_find_vars (void)
1431 {
1432 MC_PTR_FREE (old_dir);
1433 matches = 0;
1434 ignore_count = 0;
1435
1436
1437 clear_stack ();
1438
1439 g_strfreev (find_ignore_dirs);
1440 find_ignore_dirs = NULL;
1441 }
1442
1443
1444
1445 static void
1446 find_do_view_edit (gboolean unparsed_view, gboolean edit, char *dir, char *file, off_t search_start,
1447 off_t search_end)
1448 {
1449 const char *filename = NULL;
1450 int line;
1451 vfs_path_t *fullname_vpath;
1452
1453 if (content_pattern != NULL)
1454 {
1455 filename = strchr (file + 4, ':') + 1;
1456 line = atoi (file + 4);
1457 }
1458 else
1459 {
1460 filename = file + 4;
1461 line = 0;
1462 }
1463
1464 fullname_vpath = vfs_path_build_filename (dir, filename, (char *) NULL);
1465 if (edit)
1466 edit_file_at_line (fullname_vpath, use_internal_edit, line);
1467 else
1468 view_file_at_line (fullname_vpath, unparsed_view, use_internal_view, line, search_start,
1469 search_end);
1470 vfs_path_free (fullname_vpath, TRUE);
1471 }
1472
1473
1474
1475 static cb_ret_t
1476 view_edit_currently_selected_file (gboolean unparsed_view, gboolean edit)
1477 {
1478 char *text = NULL;
1479 find_match_location_t *location;
1480
1481 listbox_get_current (find_list, &text, (void **) &location);
1482
1483 if ((text == NULL) || (location == NULL) || (location->dir == NULL))
1484 return MSG_NOT_HANDLED;
1485
1486 find_do_view_edit (unparsed_view, edit, location->dir, text, location->start, location->end);
1487 return MSG_HANDLED;
1488 }
1489
1490
1491
1492 static void
1493 find_calc_button_locations (const WDialog *h, gboolean all_buttons)
1494 {
1495 const int cols = CONST_WIDGET (h)->rect.cols;
1496
1497 int l1, l2;
1498
1499 l1 = fbuts[0].len + fbuts[1].len + fbuts[is_start ? 3 : 2].len + fbuts[4].len + 3;
1500 l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len + 2;
1501
1502 fbuts[0].x = (cols - l1) / 2;
1503 fbuts[1].x = fbuts[0].x + fbuts[0].len + 1;
1504 fbuts[2].x = fbuts[1].x + fbuts[1].len + 1;
1505 fbuts[3].x = fbuts[2].x;
1506 fbuts[4].x = fbuts[2].x + fbuts[is_start ? 3 : 2].len + 1;
1507
1508 if (all_buttons)
1509 {
1510 fbuts[5].x = (cols - l2) / 2;
1511 fbuts[6].x = fbuts[5].x + fbuts[5].len + 1;
1512 fbuts[7].x = fbuts[6].x + fbuts[6].len + 1;
1513 }
1514 }
1515
1516
1517
1518 static void
1519 find_adjust_header (WDialog *h)
1520 {
1521 char title[BUF_MEDIUM];
1522 int title_len;
1523
1524 if (content_pattern != NULL)
1525 g_snprintf (title, sizeof (title), _ ("Find File: \"%s\". Content: \"%s\""), find_pattern,
1526 content_pattern);
1527 else
1528 g_snprintf (title, sizeof (title), _ ("Find File: \"%s\""), find_pattern);
1529
1530 title_len = str_term_width1 (title);
1531 if (title_len > WIDGET (h)->rect.cols - 6)
1532 {
1533
1534 title_len = WIDGET (h)->rect.cols - 6;
1535 title_len = str_column_to_pos (title, title_len);
1536 title_len -= 3;
1537 title_len = str_offset_to_pos (title, title_len);
1538
1539 memmove (title + title_len, "...", 4);
1540 }
1541
1542 frame_set_title (FRAME (h->bg), title);
1543 }
1544
1545
1546
1547 static void
1548 find_relocate_buttons (const WDialog *h, gboolean all_buttons)
1549 {
1550 size_t i;
1551
1552 find_calc_button_locations (h, all_buttons);
1553
1554 for (i = 0; i < fbuts_num; i++)
1555 fbuts[i].button->rect.x = CONST_WIDGET (h)->rect.x + fbuts[i].x;
1556 }
1557
1558
1559
1560 static cb_ret_t
1561 find_resize (WDialog *h)
1562 {
1563 Widget *w = WIDGET (h);
1564 WRect r = w->rect;
1565
1566 r.lines = LINES - 4;
1567 r.cols = COLS - 16;
1568 dlg_default_callback (w, NULL, MSG_RESIZE, 0, &r);
1569 find_adjust_header (h);
1570 find_relocate_buttons (h, TRUE);
1571
1572 return MSG_HANDLED;
1573 }
1574
1575
1576
1577 static cb_ret_t
1578 find_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
1579 {
1580 WDialog *h = DIALOG (w);
1581
1582 switch (msg)
1583 {
1584 case MSG_INIT:
1585 group_default_callback (w, NULL, MSG_INIT, 0, NULL);
1586 find_adjust_header (h);
1587 return MSG_HANDLED;
1588
1589 case MSG_KEY:
1590 if (parm == KEY_F (3) || parm == KEY_F (13))
1591 {
1592 gboolean unparsed_view = (parm == KEY_F (13));
1593
1594 return view_edit_currently_selected_file (unparsed_view, FALSE);
1595 }
1596 if (parm == KEY_F (4))
1597 return view_edit_currently_selected_file (FALSE, TRUE);
1598 return MSG_NOT_HANDLED;
1599
1600 case MSG_RESIZE:
1601 return find_resize (h);
1602
1603 case MSG_IDLE:
1604 do_search (h);
1605 return MSG_HANDLED;
1606
1607 default:
1608 return dlg_default_callback (w, sender, msg, parm, data);
1609 }
1610 }
1611
1612
1613
1614
1615 static int
1616 start_stop (WButton *button, int action)
1617 {
1618 Widget *w = WIDGET (button);
1619
1620 (void) action;
1621
1622 running = is_start;
1623 widget_idle (WIDGET (find_dlg), running);
1624 is_start = !is_start;
1625
1626 status_update (is_start ? _ ("Stopped") : _ ("Searching"));
1627 button_set_text (button, fbuts[is_start ? 3 : 2].text);
1628
1629 find_relocate_buttons (DIALOG (w->owner), FALSE);
1630 widget_draw (WIDGET (w->owner));
1631
1632 return 0;
1633 }
1634
1635
1636
1637
1638 static int
1639 find_do_view_file (WButton *button, int action)
1640 {
1641 (void) button;
1642 (void) action;
1643
1644 view_edit_currently_selected_file (FALSE, FALSE);
1645 return 0;
1646 }
1647
1648
1649
1650
1651 static int
1652 find_do_edit_file (WButton *button, int action)
1653 {
1654 (void) button;
1655 (void) action;
1656
1657 view_edit_currently_selected_file (FALSE, TRUE);
1658 return 0;
1659 }
1660
1661
1662
1663 static void
1664 setup_gui (void)
1665 {
1666 WGroup *g;
1667 size_t i;
1668 int lines, cols;
1669 int y;
1670
1671 static gboolean i18n_flag = FALSE;
1672
1673 if (!i18n_flag)
1674 {
1675 for (i = 0; i < fbuts_num; i++)
1676 {
1677 #ifdef ENABLE_NLS
1678 fbuts[i].text = _ (fbuts[i].text);
1679 #endif
1680 fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1681 if (fbuts[i].flags == DEFPUSH_BUTTON)
1682 fbuts[i].len += 2;
1683 }
1684
1685 i18n_flag = TRUE;
1686 }
1687
1688 lines = LINES - 4;
1689 cols = COLS - 16;
1690
1691 find_dlg = dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors,
1692 find_callback, NULL, "[Find File]", NULL);
1693 g = GROUP (find_dlg);
1694
1695 find_calc_button_locations (find_dlg, TRUE);
1696
1697 y = 2;
1698 find_list = listbox_new (y, 2, lines - 10, cols - 4, FALSE, NULL);
1699 group_add_widget_autopos (g, find_list, WPOS_KEEP_ALL, NULL);
1700 y += WIDGET (find_list)->rect.lines;
1701
1702 group_add_widget_autopos (g, hline_new (y++, -1, -1), WPOS_KEEP_BOTTOM, NULL);
1703
1704 found_num_label = label_new (y++, 4, NULL);
1705 group_add_widget_autopos (g, found_num_label, WPOS_KEEP_BOTTOM, NULL);
1706
1707 status_label = label_new (y++, 4, _ ("Searching"));
1708 group_add_widget_autopos (g, status_label, WPOS_KEEP_BOTTOM, NULL);
1709
1710 group_add_widget_autopos (g, hline_new (y++, -1, -1), WPOS_KEEP_BOTTOM, NULL);
1711
1712 for (i = 0; i < fbuts_num; i++)
1713 {
1714 if (i == 3)
1715 fbuts[3].button = fbuts[2].button;
1716 else
1717 {
1718 fbuts[i].button = WIDGET (button_new (y, fbuts[i].x, fbuts[i].ret_cmd, fbuts[i].flags,
1719 fbuts[i].text, fbuts[i].callback));
1720 group_add_widget_autopos (g, fbuts[i].button, WPOS_KEEP_BOTTOM, NULL);
1721 }
1722
1723 if (i == quit_button)
1724 y++;
1725 }
1726
1727 widget_select (WIDGET (find_list));
1728 }
1729
1730
1731
1732 static int
1733 run_process (void)
1734 {
1735 int ret;
1736
1737 search_content_handle = mc_search_new (content_pattern, NULL);
1738 if (search_content_handle)
1739 {
1740 search_content_handle->search_type =
1741 options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
1742 search_content_handle->is_case_sensitive = options.content_case_sens;
1743 search_content_handle->whole_words = options.content_whole_words;
1744 #ifdef HAVE_CHARSET
1745 search_content_handle->is_all_charsets = options.content_all_charsets;
1746 #endif
1747 }
1748 search_file_handle = mc_search_new (find_pattern, NULL);
1749 search_file_handle->search_type = options.file_pattern ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
1750 search_file_handle->is_case_sensitive = options.file_case_sens;
1751 #ifdef HAVE_CHARSET
1752 search_file_handle->is_all_charsets = options.file_all_charsets;
1753 #endif
1754 search_file_handle->is_entire_line = options.file_pattern;
1755
1756 resuming = FALSE;
1757
1758 widget_idle (WIDGET (find_dlg), TRUE);
1759 ret = dlg_run (find_dlg);
1760
1761 mc_search_free (search_file_handle);
1762 search_file_handle = NULL;
1763 mc_search_free (search_content_handle);
1764 search_content_handle = NULL;
1765
1766 return ret;
1767 }
1768
1769
1770
1771 static void
1772 kill_gui (void)
1773 {
1774 Widget *w = WIDGET (find_dlg);
1775
1776 widget_idle (w, FALSE);
1777 widget_destroy (w);
1778 }
1779
1780
1781
1782 static int
1783 do_find (WPanel *panel, const char *start_dir, ssize_t start_dir_len, const char *ignore_dirs,
1784 char **dirname, char **filename)
1785 {
1786 int return_value;
1787 char *dir_tmp = NULL, *file_tmp = NULL;
1788
1789 setup_gui ();
1790
1791 init_find_vars ();
1792 parse_ignore_dirs (ignore_dirs);
1793 push_directory (vfs_path_from_str (start_dir));
1794
1795 return_value = run_process ();
1796
1797
1798 init_find_vars ();
1799
1800 get_list_info (&file_tmp, &dir_tmp, NULL, NULL);
1801
1802 if (dir_tmp != NULL)
1803 *dirname = g_strdup (dir_tmp);
1804 if (file_tmp != NULL)
1805 *filename = g_strdup (file_tmp);
1806
1807 if (return_value == B_PANELIZE && *filename != NULL)
1808 {
1809 struct stat st;
1810 GList *entry;
1811 dir_list *list = &panel->dir;
1812 char *name = NULL;
1813 gboolean ok = TRUE;
1814
1815 panel_clean_dir (panel);
1816 dir_list_init (list);
1817
1818 for (entry = listbox_get_first_link (find_list); entry != NULL && ok;
1819 entry = g_list_next (entry))
1820 {
1821 const char *lc_filename;
1822 WLEntry *le = LENTRY (entry->data);
1823 find_match_location_t *location = le->data;
1824 char *p;
1825 gboolean link_to_dir, stale_link;
1826
1827 if ((le->text == NULL) || (location == NULL) || (location->dir == NULL))
1828 continue;
1829
1830 if (!content_is_empty)
1831 lc_filename = strchr (le->text + 4, ':') + 1;
1832 else
1833 lc_filename = le->text + 4;
1834
1835 name = mc_build_filename (location->dir, lc_filename, (char *) NULL);
1836
1837 p = name;
1838 if (start_dir_len > 0)
1839 p += (size_t) start_dir_len;
1840 if (IS_PATH_SEP (*p))
1841 p++;
1842
1843 if (!handle_path (p, &st, &link_to_dir, &stale_link))
1844 {
1845 g_free (name);
1846 continue;
1847 }
1848
1849
1850 if (!content_is_empty && list->len != 0
1851 && strcmp (list->list[list->len - 1].fname->str, p) == 0)
1852 {
1853 g_free (name);
1854 continue;
1855 }
1856
1857 ok = dir_list_append (list, p, &st, link_to_dir, stale_link);
1858
1859 g_free (name);
1860
1861 if ((list->len & 15) == 0)
1862 rotate_dash (TRUE);
1863 }
1864
1865 panel->is_panelized = TRUE;
1866 panel_panelize_absolutize_if_needed (panel);
1867 panel_panelize_save (panel);
1868 }
1869
1870 kill_gui ();
1871 do_search (NULL);
1872 MC_PTR_FREE (old_dir);
1873 rotate_dash (FALSE);
1874
1875 return return_value;
1876 }
1877
1878
1879
1880
1881
1882 void
1883 find_cmd (WPanel *panel)
1884 {
1885 char *start_dir = NULL, *ignore_dirs = NULL;
1886 ssize_t start_dir_len;
1887
1888 find_pattern = NULL;
1889 content_pattern = NULL;
1890
1891 while (find_parameters (panel, &start_dir, &start_dir_len, &ignore_dirs, &find_pattern,
1892 &content_pattern))
1893 {
1894 char *filename = NULL, *dirname = NULL;
1895 int v = B_CANCEL;
1896
1897 content_is_empty = content_pattern == NULL;
1898
1899 if (find_pattern[0] != '\0')
1900 {
1901 last_refresh = 0;
1902
1903 is_start = FALSE;
1904
1905 if (!content_is_empty && !str_is_valid_string (content_pattern))
1906 MC_PTR_FREE (content_pattern);
1907
1908 v = do_find (panel, start_dir, start_dir_len, ignore_dirs, &dirname, &filename);
1909 }
1910
1911 g_free (start_dir);
1912 g_free (ignore_dirs);
1913 MC_PTR_FREE (find_pattern);
1914
1915 if (v == B_ENTER)
1916 {
1917 if (dirname != NULL)
1918 {
1919 vfs_path_t *dirname_vpath;
1920
1921 dirname_vpath = vfs_path_from_str (dirname);
1922 panel_cd (panel, dirname_vpath, cd_exact);
1923 vfs_path_free (dirname_vpath, TRUE);
1924
1925 if (filename != NULL)
1926 {
1927 size_t offset;
1928
1929 if (content_pattern == NULL)
1930 offset = 4;
1931 else
1932 offset = strchr (filename + 4, ':') - filename + 1;
1933
1934 panel_set_current_by_name (panel, filename + offset);
1935 }
1936 }
1937 else if (filename != NULL)
1938 {
1939 vfs_path_t *filename_vpath;
1940
1941 filename_vpath = vfs_path_from_str (filename);
1942 panel_cd (panel, filename_vpath, cd_exact);
1943 vfs_path_free (filename_vpath, TRUE);
1944 }
1945 }
1946
1947 MC_PTR_FREE (content_pattern);
1948 g_free (dirname);
1949 g_free (filename);
1950
1951 if (v == B_ENTER || v == B_CANCEL)
1952 break;
1953
1954 if (v == B_PANELIZE)
1955 {
1956 panel_re_sort (panel);
1957 panel_set_current_by_name (panel, NULL);
1958 break;
1959 }
1960 }
1961 }
1962
1963