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