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