2 Find file command for the Midnight Commander
4 Copyright (C) 1995-2016
5 Free Software Foundation, Inc.
9 Slava Zanko <slavazanko@gmail.com>, 2013
10 Andrew Borodin <aborodin@vmail.ru>, 2013
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 * \brief Source: Find file command
41 #include "lib/global.h"
43 #include "lib/tty/tty.h"
44 #include "lib/tty/key.h"
46 #include "lib/search.h"
47 #include "lib/mcconfig.h"
48 #include "lib/vfs/vfs.h"
49 #include "lib/strutil.h"
50 #include "lib/widget.h"
51 #include "lib/util.h" /* canonicalize_pathname() */
53 #include "src/setup.h" /* verbose */
54 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
57 #include "cmd.h" /* view_file_at_line() */
58 #include "midnight.h" /* current_panel */
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 #define MAX_REFRESH_INTERVAL (G_USEC_PER_SEC / 20) /* 50 ms */
69 #define MIN_REFRESH_FILE_SIZE (256 * 1024) /* 256 KB */
71 /*** file scope type declarations ****************************************************************/
73 /* A couple of extra messages we need */
90 /* find file options */
93 /* file name options */
94 gboolean file_case_sens
;
95 gboolean file_pattern
;
98 gboolean file_all_charsets
;
100 /* file content options */
101 gboolean content_case_sens
;
102 gboolean content_regexp
;
103 gboolean content_first_hit
;
104 gboolean content_whole_words
;
105 gboolean content_all_charsets
;
107 /* whether use ignore dirs or not */
108 gboolean ignore_dirs_enable
;
109 /* list of directories to be ignored, separated by ':' */
111 } find_file_options_t
;
118 } find_match_location_t
;
120 /*** file scope variables ************************************************************************/
122 /* button callbacks */
123 static int start_stop (WButton
* button
, int action
);
124 static int find_do_view_file (WButton
* button
, int action
);
125 static int find_do_edit_file (WButton
* button
, int action
);
127 /* Parsed ignore dirs */
128 static char **find_ignore_dirs
= NULL
;
130 /* static variables to remember find parameters */
131 static WInput
*in_start
; /* Start path */
132 static WInput
*in_name
; /* Filename */
133 static WInput
*in_with
; /* Text */
134 static WInput
*in_ignore
;
135 static WLabel
*content_label
; /* 'Content:' label */
136 static WCheck
*file_case_sens_cbox
; /* "case sensitive" checkbox */
137 static WCheck
*file_pattern_cbox
; /* File name is glob or regexp */
138 static WCheck
*recursively_cbox
;
139 static WCheck
*skip_hidden_cbox
;
140 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
141 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
142 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
143 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
145 static WCheck
*file_all_charsets_cbox
;
146 static WCheck
*content_all_charsets_cbox
;
148 static WCheck
*ignore_dirs_cbox
;
150 static gboolean running
= FALSE
; /* nice flag */
151 static char *find_pattern
= NULL
; /* Pattern to search */
152 static char *content_pattern
= NULL
; /* pattern to search inside files; if
153 content_regexp_flag is true, it contains the
154 regex pattern, else the search string. */
155 static unsigned long matches
; /* Number of matches */
156 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
157 static char *old_dir
= NULL
;
159 static struct timeval last_refresh
;
161 /* Where did we stop */
162 static gboolean resuming
;
163 static int last_line
;
165 static off_t last_off
;
168 static size_t ignore_count
= 0;
170 static WDialog
*find_dlg
; /* The dialog */
171 static WLabel
*status_label
; /* Finished, Searching etc. */
172 static WLabel
*found_num_label
; /* Number of found items */
174 /* This keeps track of the directory stack */
175 static GQueue dir_queue
= G_QUEUE_INIT
;
181 button_flags_t flags
;
183 int len
; /* length including space and brackets */
189 { B_ENTER
, DEFPUSH_BUTTON
, N_("&Chdir"), 0, 0, NULL
, NULL
},
190 { B_AGAIN
, NORMAL_BUTTON
, N_("&Again"), 0, 0, NULL
, NULL
},
191 { B_STOP
, NORMAL_BUTTON
, N_("S&uspend"), 0, 0, NULL
, start_stop
},
192 { B_STOP
, NORMAL_BUTTON
, N_("Con&tinue"), 0, 0, NULL
, NULL
},
193 { B_CANCEL
, NORMAL_BUTTON
, N_("&Quit"), 0, 0, NULL
, NULL
},
195 { B_PANELIZE
, NORMAL_BUTTON
, N_("Pane&lize"), 0, 0, NULL
, NULL
},
196 { B_VIEW
, NORMAL_BUTTON
, N_("&View - F3"), 0, 0, NULL
, find_do_view_file
},
197 { B_VIEW
, NORMAL_BUTTON
, N_("&Edit - F4"), 0, 0, NULL
, find_do_edit_file
}
201 static const size_t fbuts_num
= G_N_ELEMENTS (fbuts
);
202 static const size_t quit_button
= 4; /* index of "Quit" button */
204 static WListbox
*find_list
; /* Listbox with the file list */
206 static find_file_options_t options
= {
207 TRUE
, TRUE
, TRUE
, FALSE
, FALSE
,
208 TRUE
, FALSE
, FALSE
, FALSE
, FALSE
,
212 static char *in_start_dir
= INPUT_LAST_TEXT
;
214 static mc_search_t
*search_file_handle
= NULL
;
215 static mc_search_t
*search_content_handle
= NULL
;
217 /* --------------------------------------------------------------------------------------------- */
218 /*** file scope functions ************************************************************************/
219 /* --------------------------------------------------------------------------------------------- */
221 /* don't use max macro to avoid double str_term_width1() call in widget length caclulation */
227 return (a
> b
? a
: b
);
230 /* --------------------------------------------------------------------------------------------- */
233 parse_ignore_dirs (const char *ignore_dirs
)
235 size_t r
= 0, w
= 0; /* read and write iterators */
237 if (!options
.ignore_dirs_enable
|| ignore_dirs
== NULL
|| ignore_dirs
[0] == '\0')
240 find_ignore_dirs
= g_strsplit (ignore_dirs
, ":", -1);
242 /* Values like '/foo::/bar: produce holes in list.
243 * Find and remove them */
244 for (; find_ignore_dirs
[r
] != NULL
; r
++)
246 if (find_ignore_dirs
[r
][0] == '\0')
248 /* empty entry -- skip it */
249 MC_PTR_FREE (find_ignore_dirs
[r
]);
255 /* copy entry to the previous free array cell */
256 find_ignore_dirs
[w
] = find_ignore_dirs
[r
];
257 find_ignore_dirs
[r
] = NULL
;
260 canonicalize_pathname (find_ignore_dirs
[w
]);
261 if (find_ignore_dirs
[w
][0] != '\0')
264 MC_PTR_FREE (find_ignore_dirs
[w
]);
267 if (find_ignore_dirs
[0] == NULL
)
269 g_strfreev (find_ignore_dirs
);
270 find_ignore_dirs
= NULL
;
274 /* --------------------------------------------------------------------------------------------- */
277 find_load_options (void)
279 static gboolean loaded
= FALSE
;
286 options
.file_case_sens
=
287 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_case_sens", TRUE
);
288 options
.file_pattern
=
289 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_shell_pattern", TRUE
);
290 options
.find_recurs
=
291 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_find_recurs", TRUE
);
292 options
.skip_hidden
=
293 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_skip_hidden", FALSE
);
294 options
.file_all_charsets
=
295 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_all_charsets", FALSE
);
296 options
.content_case_sens
=
297 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_case_sens", TRUE
);
298 options
.content_regexp
=
299 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_regexp", FALSE
);
300 options
.content_first_hit
=
301 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_first_hit", FALSE
);
302 options
.content_whole_words
=
303 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_whole_words", FALSE
);
304 options
.content_all_charsets
=
305 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_all_charsets", FALSE
);
306 options
.ignore_dirs_enable
=
307 mc_config_get_bool (mc_global
.main_config
, "FindFile", "ignore_dirs_enable", TRUE
);
308 options
.ignore_dirs
=
309 mc_config_get_string (mc_global
.main_config
, "FindFile", "ignore_dirs", "");
311 if (options
.ignore_dirs
[0] == '\0')
312 MC_PTR_FREE (options
.ignore_dirs
);
315 /* --------------------------------------------------------------------------------------------- */
318 find_save_options (void)
320 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_case_sens",
321 options
.file_case_sens
);
322 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_shell_pattern",
323 options
.file_pattern
);
324 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_find_recurs", options
.find_recurs
);
325 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_skip_hidden", options
.skip_hidden
);
326 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_all_charsets",
327 options
.file_all_charsets
);
328 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_case_sens",
329 options
.content_case_sens
);
330 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_regexp",
331 options
.content_regexp
);
332 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_first_hit",
333 options
.content_first_hit
);
334 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_whole_words",
335 options
.content_whole_words
);
336 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_all_charsets",
337 options
.content_all_charsets
);
338 mc_config_set_bool (mc_global
.main_config
, "FindFile", "ignore_dirs_enable",
339 options
.ignore_dirs_enable
);
340 mc_config_set_string (mc_global
.main_config
, "FindFile", "ignore_dirs", options
.ignore_dirs
);
343 /* --------------------------------------------------------------------------------------------- */
346 add_to_list (const char *text
, void *data
)
348 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
, TRUE
);
351 /* --------------------------------------------------------------------------------------------- */
354 stop_idle (void *data
)
356 widget_idle (WIDGET (data
), FALSE
);
359 /* --------------------------------------------------------------------------------------------- */
362 status_update (const char *text
)
364 label_set_text (status_label
, text
);
367 /* --------------------------------------------------------------------------------------------- */
370 found_num_update (void)
372 char buffer
[BUF_TINY
];
373 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
374 label_set_text (found_num_label
, buffer
);
377 /* --------------------------------------------------------------------------------------------- */
380 get_list_info (char **file
, char **dir
, gsize
* start
, gsize
* end
)
382 find_match_location_t
*location
;
384 listbox_get_current (find_list
, file
, (void **) &location
);
385 if (location
!= NULL
)
388 *dir
= location
->dir
;
390 *start
= location
->start
;
392 *end
= location
->end
;
401 /* --------------------------------------------------------------------------------------------- */
402 /** check regular expression */
405 find_check_regexp (const char *r
)
408 gboolean regexp_ok
= FALSE
;
410 search
= mc_search_new (r
, NULL
);
414 search
->search_type
= MC_SEARCH_T_REGEX
;
415 regexp_ok
= mc_search_prepare (search
);
416 mc_search_free (search
);
422 /* --------------------------------------------------------------------------------------------- */
425 find_toggle_enable_params (void)
427 gboolean disable
= in_name
->buffer
[0] == '\0';
429 widget_disable (WIDGET (file_pattern_cbox
), disable
);
430 widget_disable (WIDGET (file_case_sens_cbox
), disable
);
432 widget_disable (WIDGET (file_all_charsets_cbox
), disable
);
436 /* --------------------------------------------------------------------------------------------- */
439 find_toggle_enable_content (void)
441 gboolean disable
= in_with
->buffer
[0] == '\0';
443 widget_disable (WIDGET (content_regexp_cbox
), disable
);
444 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
446 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
448 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
449 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
452 /* --------------------------------------------------------------------------------------------- */
454 * Callback for the parameter dialog.
455 * Validate regex, prevent closing the dialog if it's invalid.
459 find_parm_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
461 /* FIXME: HACK: use first draw of dialog to resolve widget state dependencies.
462 * Use this time moment to check input field content. We can't do that in MSG_INIT
463 * because history is not loaded yet.
464 * Probably, we want new MSG_ACTIVATE message as complement to MSG_VALIDATE one. Or
465 * we could name it MSG_POST_INIT.
467 * In one or two other places we use MSG_IDLE instead of MSG_DRAW for a similar
468 * purpose. We should remember to fix those places too when we introduce the new
471 static gboolean first_draw
= TRUE
;
473 WDialog
*h
= DIALOG (w
);
482 if (sender
== WIDGET (ignore_dirs_cbox
))
484 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
486 widget_disable (WIDGET (in_ignore
), disable
);
491 return MSG_NOT_HANDLED
;
494 if (h
->ret_value
!= B_ENTER
)
497 /* check filename regexp */
498 if (!(file_pattern_cbox
->state
& C_BOOL
)
499 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->buffer
))
501 /* Don't stop the dialog */
502 widget_set_state (WIDGET (h
), WST_ACTIVE
, TRUE
);
503 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
504 dlg_select_widget (in_name
);
508 /* check content regexp */
509 if ((content_regexp_cbox
->state
& C_BOOL
) && (in_with
->buffer
[0] != '\0')
510 && !find_check_regexp (in_with
->buffer
))
512 /* Don't stop the dialog */
513 widget_set_state (WIDGET (h
), WST_ACTIVE
, TRUE
);
514 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
515 dlg_select_widget (in_with
);
522 if (h
->current
->data
== in_name
)
523 find_toggle_enable_params ();
524 else if (h
->current
->data
== in_with
)
525 find_toggle_enable_content ();
531 find_toggle_enable_params ();
532 find_toggle_enable_content ();
536 /* fall through to call MSG_DRAW default handler */
539 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
543 /* --------------------------------------------------------------------------------------------- */
545 * find_parameters: gets information from the user
547 * If the return value is TRUE, then the following holds:
549 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
550 * They are newly allocated strings and must be freed when uneeded.
552 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
553 * of start_dir (which is absolute). It is used to get a relative pats of find results.
557 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
558 char **ignore_dirs
, char **pattern
, char **content
)
560 /* Size of the find parameters window */
562 const int lines
= 18;
564 const int lines
= 17;
568 gboolean return_value
;
571 const char *file_name_label
= N_("File name:");
572 const char *file_recurs_label
= N_("&Find recursively");
573 const char *file_pattern_label
= N_("&Using shell patterns");
575 const char *file_all_charsets_label
= N_("&All charsets");
577 const char *file_case_label
= N_("Cas&e sensitive");
578 const char *file_skip_hidden_label
= N_("S&kip hidden");
581 const char *content_content_label
= N_("Content:");
582 const char *content_use_label
= N_("Sea&rch for content");
583 const char *content_regexp_label
= N_("Re&gular expression");
584 const char *content_case_label
= N_("Case sens&itive");
586 const char *content_all_charsets_label
= N_("A&ll charsets");
588 const char *content_whole_words_label
= N_("&Whole words");
589 const char *content_first_hit_label
= N_("Fir&st hit");
591 const char *buts
[] = { N_("&Tree"), N_("&OK"), N_("&Cancel") };
603 file_name_label
= _(file_name_label
);
604 file_recurs_label
= _(file_recurs_label
);
605 file_pattern_label
= _(file_pattern_label
);
607 file_all_charsets_label
= _(file_all_charsets_label
);
609 file_case_label
= _(file_case_label
);
610 file_skip_hidden_label
= _(file_skip_hidden_label
);
613 content_content_label
= _(content_content_label
);
614 content_use_label
= _(content_use_label
);
615 content_regexp_label
= _(content_regexp_label
);
616 content_case_label
= _(content_case_label
);
618 content_all_charsets_label
= _(content_all_charsets_label
);
620 content_whole_words_label
= _(content_whole_words_label
);
621 content_first_hit_label
= _(content_first_hit_label
);
623 for (i
= 0; i
< G_N_ELEMENTS (buts
); i
++)
624 buts
[i
] = _(buts
[i
]);
626 #endif /* ENABLE_NLS */
628 /* caclulate dialog width */
631 cw
= str_term_width1 (file_name_label
);
632 cw
= max (cw
, str_term_width1 (file_recurs_label
) + 4);
633 cw
= max (cw
, str_term_width1 (file_pattern_label
) + 4);
635 cw
= max (cw
, str_term_width1 (file_all_charsets_label
) + 4);
637 cw
= max (cw
, str_term_width1 (file_case_label
) + 4);
638 cw
= max (cw
, str_term_width1 (file_skip_hidden_label
) + 4);
640 cw
= max (cw
, str_term_width1 (content_content_label
) + 4);
641 cw
= max (cw
, str_term_width1 (content_use_label
) + 4);
642 cw
= max (cw
, str_term_width1 (content_regexp_label
) + 4);
643 cw
= max (cw
, str_term_width1 (content_case_label
) + 4);
645 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);
651 b0
= str_term_width1 (buts
[0]) + 3;
652 b1
= str_term_width1 (buts
[1]) + 5; /* default button */
653 b2
= str_term_width1 (buts
[2]) + 3;
656 cols
= max (cols
, max (b12
, cw
* 2 + 1) + 6);
658 find_load_options ();
660 if (in_start_dir
== NULL
)
661 in_start_dir
= g_strdup (".");
664 dlg_create (TRUE
, 0, 0, lines
, cols
, dialog_colors
, find_parm_callback
, NULL
, "[Find File]",
665 _("Find File"), DLG_CENTER
);
672 add_widget (find_dlg
, label_new (y1
++, x1
, _("Start at:")));
674 input_new (y1
, x1
, input_colors
, cols
- b0
- 7, in_start_dir
, "start",
675 INPUT_COMPLETE_CD
| INPUT_COMPLETE_FILENAMES
);
676 add_widget (find_dlg
, in_start
);
678 add_widget (find_dlg
, button_new (y1
++, cols
- b0
- 3, B_TREE
, NORMAL_BUTTON
, buts
[0], NULL
));
681 check_new (y1
++, x1
, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
682 add_widget (find_dlg
, ignore_dirs_cbox
);
685 input_new (y1
++, x1
, input_colors
, cols
- 6,
686 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "", "ignoredirs",
687 INPUT_COMPLETE_CD
| INPUT_COMPLETE_FILENAMES
);
688 add_widget (find_dlg
, in_ignore
);
690 add_widget (find_dlg
, hline_new (y1
++, -1, -1));
694 /* Start 1st column */
695 add_widget (find_dlg
, label_new (y1
++, x1
, file_name_label
));
697 input_new (y1
++, x1
, input_colors
, cw
, INPUT_LAST_TEXT
, "name",
698 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
699 add_widget (find_dlg
, in_name
);
701 /* Start 2nd column */
702 content_label
= label_new (y2
++, x2
, content_content_label
);
703 add_widget (find_dlg
, content_label
);
705 input_new (y2
++, x2
, input_colors
, cw
, INPUT_LAST_TEXT
,
706 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_NONE
);
707 in_with
->label
= content_label
;
708 add_widget (find_dlg
, in_with
);
710 /* Continue 1st column */
711 recursively_cbox
= check_new (y1
++, x1
, options
.find_recurs
, file_recurs_label
);
712 add_widget (find_dlg
, recursively_cbox
);
714 file_pattern_cbox
= check_new (y1
++, x1
, options
.file_pattern
, file_pattern_label
);
715 add_widget (find_dlg
, file_pattern_cbox
);
717 file_case_sens_cbox
= check_new (y1
++, x1
, options
.file_case_sens
, file_case_label
);
718 add_widget (find_dlg
, file_case_sens_cbox
);
721 file_all_charsets_cbox
=
722 check_new (y1
++, x1
, options
.file_all_charsets
, file_all_charsets_label
);
723 add_widget (find_dlg
, file_all_charsets_cbox
);
726 skip_hidden_cbox
= check_new (y1
++, x1
, options
.skip_hidden
, file_skip_hidden_label
);
727 add_widget (find_dlg
, skip_hidden_cbox
);
729 /* Continue 2nd column */
730 content_whole_words_cbox
=
731 check_new (y2
++, x2
, options
.content_whole_words
, content_whole_words_label
);
732 add_widget (find_dlg
, content_whole_words_cbox
);
734 content_regexp_cbox
= check_new (y2
++, x2
, options
.content_regexp
, content_regexp_label
);
735 add_widget (find_dlg
, content_regexp_cbox
);
737 content_case_sens_cbox
= check_new (y2
++, x2
, options
.content_case_sens
, content_case_label
);
738 add_widget (find_dlg
, content_case_sens_cbox
);
741 content_all_charsets_cbox
=
742 check_new (y2
++, x2
, options
.content_all_charsets
, content_all_charsets_label
);
743 add_widget (find_dlg
, content_all_charsets_cbox
);
746 content_first_hit_cbox
=
747 check_new (y2
++, x2
, options
.content_first_hit
, content_first_hit_label
);
748 add_widget (find_dlg
, content_first_hit_cbox
);
752 x1
= (cols
- b12
) / 2;
753 add_widget (find_dlg
, hline_new (y1
++, -1, -1));
754 add_widget (find_dlg
, button_new (y1
, x1
, B_ENTER
, DEFPUSH_BUTTON
, buts
[1], NULL
));
755 add_widget (find_dlg
, button_new (y1
, x1
+ b1
+ 1, B_CANCEL
, NORMAL_BUTTON
, buts
[2], NULL
));
758 dlg_select_widget (in_name
);
760 switch (dlg_run (find_dlg
))
763 return_value
= FALSE
;
770 temp_dir
= in_start
->buffer
;
771 if (*temp_dir
== '\0' || DIR_IS_DOT (temp_dir
))
772 temp_dir
= g_strdup (vfs_path_as_str (current_panel
->cwd_vpath
));
774 temp_dir
= g_strdup (temp_dir
);
776 if (in_start_dir
!= INPUT_LAST_TEXT
)
777 g_free (in_start_dir
);
778 in_start_dir
= tree_box (temp_dir
);
779 if (in_start_dir
== NULL
)
780 in_start_dir
= temp_dir
;
784 input_assign_text (in_start
, in_start_dir
);
786 /* Warning: Dreadful goto */
795 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
796 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
798 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
799 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
800 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
801 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
802 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
803 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
804 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
805 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
806 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
807 g_free (options
.ignore_dirs
);
808 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
810 *content
= in_with
->buffer
[0] != '\0' ? g_strdup (in_with
->buffer
) : NULL
;
811 if (in_name
->buffer
[0] != '\0')
812 *pattern
= g_strdup (in_name
->buffer
);
814 *pattern
= g_strdup (options
.file_pattern
? "*" : ".*");
815 *start_dir
= !input_is_empty (in_start
) ? in_start
->buffer
: (char *) ".";
816 if (in_start_dir
!= INPUT_LAST_TEXT
)
817 g_free (in_start_dir
);
818 in_start_dir
= g_strdup (*start_dir
);
820 s
= tilde_expand (*start_dir
);
821 canonicalize_pathname (s
);
825 *start_dir
= g_strdup (vfs_path_as_str (current_panel
->cwd_vpath
));
826 /* FIXME: is current_panel->cwd_vpath canonicalized? */
827 /* relative paths will be used in panelization */
828 *start_dir_len
= (ssize_t
) strlen (*start_dir
);
831 else if (g_path_is_absolute (s
))
838 /* relative paths will be used in panelization */
840 mc_build_filename (vfs_path_as_str (current_panel
->cwd_vpath
), s
,
842 *start_dir_len
= (ssize_t
) strlen (vfs_path_as_str (current_panel
->cwd_vpath
));
846 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
847 || DIR_IS_DOT (in_ignore
->buffer
))
850 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
852 find_save_options ();
858 dlg_destroy (find_dlg
);
863 /* --------------------------------------------------------------------------------------------- */
866 push_directory (vfs_path_t
* dir
)
868 g_queue_push_head (&dir_queue
, (void *) dir
);
871 /* --------------------------------------------------------------------------------------------- */
873 static inline vfs_path_t
*
876 return (vfs_path_t
*) g_queue_pop_tail (&dir_queue
);
879 /* --------------------------------------------------------------------------------------------- */
880 /** Remove all the items from the stack */
885 g_queue_foreach (&dir_queue
, (GFunc
) vfs_path_free
, NULL
);
886 g_queue_clear (&dir_queue
);
889 /* --------------------------------------------------------------------------------------------- */
892 insert_file (const char *dir
, const char *file
, gsize start
, gsize end
)
894 char *tmp_name
= NULL
;
895 static char *dirname
= NULL
;
896 find_match_location_t
*location
;
898 while (IS_PATH_SEP (dir
[0]) && IS_PATH_SEP (dir
[1]))
903 if (strcmp (old_dir
, dir
))
906 old_dir
= g_strdup (dir
);
907 dirname
= add_to_list (dir
, NULL
);
912 old_dir
= g_strdup (dir
);
913 dirname
= add_to_list (dir
, NULL
);
916 tmp_name
= g_strdup_printf (" %s", file
);
917 location
= g_malloc (sizeof (*location
));
918 location
->dir
= dirname
;
919 location
->start
= start
;
921 add_to_list (tmp_name
, location
);
925 /* --------------------------------------------------------------------------------------------- */
928 find_add_match (const char *dir
, const char *file
, gsize start
, gsize end
)
930 insert_file (dir
, file
, start
, end
);
934 listbox_select_first (find_list
);
935 widget_redraw (WIDGET (find_list
));
941 /* --------------------------------------------------------------------------------------------- */
943 static FindProgressStatus
944 check_find_events (WDialog
* h
)
950 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
953 dlg_process_event (h
, c
, &event
);
954 if (h
->ret_value
== B_ENTER
955 || h
->ret_value
== B_CANCEL
|| h
->ret_value
== B_AGAIN
|| h
->ret_value
== B_PANELIZE
)
957 /* dialog terminated */
960 if (!widget_get_state (WIDGET (h
), WST_IDLE
))
962 /* searching suspended */
970 /* --------------------------------------------------------------------------------------------- */
974 * Search the content_pattern string in the DIRECTORY/FILE.
975 * It will add the found entries to the find listbox.
977 * returns FALSE if do_search should look for another file
978 * TRUE if do_search should exit and proceed to the event handler
982 search_content (WDialog
* h
, const char *directory
, const char *filename
)
985 char buffer
[BUF_4K
]; /* raw input buffer */
987 gboolean ret_val
= FALSE
;
991 suseconds_t useconds
;
992 gboolean status_updated
= FALSE
;
994 vpath
= vfs_path_build_filename (directory
, filename
, (char *) NULL
);
996 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
998 vfs_path_free (vpath
);
1002 file_fd
= mc_open (vpath
, O_RDONLY
);
1003 vfs_path_free (vpath
);
1008 /* get time elapsed from last refresh */
1009 if (gettimeofday (&tv
, NULL
) == -1)
1015 seconds
= tv
.tv_sec
- last_refresh
.tv_sec
;
1016 useconds
= tv
.tv_usec
- last_refresh
.tv_usec
;
1020 useconds
+= G_USEC_PER_SEC
;
1023 if (s
.st_size
>= MIN_REFRESH_FILE_SIZE
|| seconds
> 0 || useconds
> MAX_REFRESH_INTERVAL
)
1025 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), filename
);
1026 status_update (str_trunc (buffer
, WIDGET (h
)->cols
- 8));
1029 status_updated
= TRUE
;
1032 tty_enable_interrupt_key ();
1033 tty_got_interrupt ();
1039 off_t off
= 0; /* file_fd's offset corresponding to strbuf[0] */
1040 gboolean found
= FALSE
;
1043 char result
[BUF_MEDIUM
];
1044 char *strbuf
= NULL
; /* buffer for fetched string */
1045 int strbuf_size
= 0;
1046 int i
= -1; /* compensate for a newline we'll add when we first enter the loop */
1050 /* We've been previously suspended, start from the previous position */
1061 off
+= i
+ 1; /* the previous line, plus a newline character */
1064 /* read to buffer and get line from there */
1070 n_read
= mc_read (file_fd
, buffer
, sizeof (buffer
));
1078 /* skip possible leading zero(s) */
1087 if (i
>= strbuf_size
- 1)
1090 strbuf
= g_realloc (strbuf
, strbuf_size
);
1105 /* if (ch == '\n'): do not search in empty strings */
1111 if (!found
/* Search in binary line once */
1112 && mc_search_run (search_content_handle
, (const void *) strbuf
, 0, i
, &found_len
))
1114 if (!status_updated
)
1116 /* if we add results for a file, we have to ensure that
1117 name of this file is shown in status bar */
1118 g_snprintf (result
, sizeof (result
), _("Grepping in %s"), filename
);
1119 status_update (str_trunc (result
, WIDGET (h
)->cols
- 8));
1122 status_updated
= TRUE
;
1125 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1126 found_start
= off
+ search_content_handle
->normal_offset
+ 1; /* off by one: ticket 3280 */
1127 find_add_match (directory
, result
, found_start
, found_start
+ found_len
);
1131 if (found
&& options
.content_first_hit
)
1141 if ((line
& 0xff) == 0)
1143 FindProgressStatus res
;
1144 res
= check_find_events (h
);
1168 tty_disable_interrupt_key ();
1173 /* --------------------------------------------------------------------------------------------- */
1176 If dir is absolute, this means we're within dir and searching file here.
1177 If dir is relative, this means we're going to add dir to the directory stack.
1180 find_ignore_dir_search (const char *dir
)
1182 if (find_ignore_dirs
!= NULL
)
1184 const size_t dlen
= strlen (dir
);
1185 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1189 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1191 const size_t ilen
= strlen (*ignore_dir
);
1192 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1194 /* ignore dir is too long -- skip it */
1198 /* handle absolute and relative paths */
1199 switch (iabs
| dabs
)
1201 case 0: /* both paths are relative */
1202 case 3: /* both paths are abolute */
1203 /* if ignore dir is not a path of dir -- skip it */
1204 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1206 /* be sure that ignore dir is not a part of dir like:
1207 ignore dir is "h", dir is "home" */
1208 if (dir
[ilen
] == '\0' || IS_PATH_SEP (dir
[ilen
]))
1212 case 1: /* dir is absolute, ignore_dir is relative */
1216 d
= strstr (dir
, *ignore_dir
);
1217 if (d
!= NULL
&& IS_PATH_SEP (d
[-1])
1218 && (d
[ilen
] == '\0' || IS_PATH_SEP (d
[ilen
])))
1222 case 2: /* dir is relative, ignore_dir is absolute */
1223 /* FIXME: skip this case */
1225 default: /* this cannot occurs */
1234 /* --------------------------------------------------------------------------------------------- */
1237 find_rotate_dash (const WDialog
* h
, gboolean show
)
1239 static size_t pos
= 0;
1240 static const char rotating_dash
[4] = "|/-\\";
1241 const Widget
*w
= CONST_WIDGET (h
);
1246 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1247 widget_move (h
, w
->lines
- 7, w
->cols
- 4);
1248 tty_print_char (show
? rotating_dash
[pos
] : ' ');
1249 pos
= (pos
+ 1) % sizeof (rotating_dash
);
1253 /* --------------------------------------------------------------------------------------------- */
1256 do_search (WDialog
* h
)
1258 static struct dirent
*dp
= NULL
;
1259 static DIR *dirp
= NULL
;
1260 static char *directory
= NULL
;
1261 struct stat tmp_stat
;
1263 unsigned short count
;
1266 { /* someone forces me to close dirp */
1272 MC_PTR_FREE (directory
);
1277 for (count
= 0; count
< 32; count
++)
1287 while (dirp
== NULL
)
1289 vfs_path_t
*tmp_vpath
= NULL
;
1291 tty_setcolor (REVERSE_COLOR
);
1295 tmp_vpath
= pop_directory ();
1296 if (tmp_vpath
== NULL
)
1299 if (ignore_count
== 0)
1300 status_update (_("Finished"));
1303 char msg
[BUF_SMALL
];
1304 g_snprintf (msg
, sizeof (msg
),
1305 ngettext ("Finished (ignored %zd directory)",
1306 "Finished (ignored %zd directories)",
1307 ignore_count
), ignore_count
);
1308 status_update (msg
);
1310 find_rotate_dash (h
, FALSE
);
1315 /* handle absolute ignore dirs here */
1319 ok
= find_ignore_dir_search (vfs_path_as_str (tmp_vpath
));
1324 vfs_path_free (tmp_vpath
);
1329 directory
= g_strdup (vfs_path_as_str (tmp_vpath
));
1333 char buffer
[BUF_MEDIUM
];
1335 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"), directory
);
1336 status_update (str_trunc (directory
, WIDGET (h
)->cols
- 8));
1339 dirp
= mc_opendir (tmp_vpath
);
1340 vfs_path_free (tmp_vpath
);
1341 } /* while (!dirp) */
1343 /* skip invalid filenames */
1344 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1348 if (DIR_IS_DOT (dp
->d_name
) || DIR_IS_DOTDOT (dp
->d_name
))
1350 /* skip invalid filenames */
1351 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1357 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1361 if (options
.find_recurs
&& (directory
!= NULL
))
1362 { /* Can directory be NULL ? */
1363 /* handle relative ignore dirs here */
1364 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1368 vfs_path_t
*tmp_vpath
;
1370 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1372 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1373 push_directory (tmp_vpath
);
1375 vfs_path_free (tmp_vpath
);
1379 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1380 0, strlen (dp
->d_name
), &bytes_found
);
1384 if (content_pattern
== NULL
)
1385 find_add_match (directory
, dp
->d_name
, 0, 0);
1386 else if (search_content (h
, directory
, dp
->d_name
))
1391 /* skip invalid filenames */
1392 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1396 find_rotate_dash (h
, TRUE
);
1401 /* --------------------------------------------------------------------------------------------- */
1404 init_find_vars (void)
1406 MC_PTR_FREE (old_dir
);
1410 /* Remove all the items from the stack */
1413 g_strfreev (find_ignore_dirs
);
1414 find_ignore_dirs
= NULL
;
1417 /* --------------------------------------------------------------------------------------------- */
1420 find_do_view_edit (gboolean unparsed_view
, gboolean edit
, char *dir
, char *file
, off_t search_start
,
1423 char *fullname
= NULL
;
1424 const char *filename
= NULL
;
1426 vfs_path_t
*fullname_vpath
;
1428 if (content_pattern
!= NULL
)
1430 filename
= strchr (file
+ 4, ':') + 1;
1431 line
= atoi (file
+ 4);
1435 filename
= file
+ 4;
1439 fullname_vpath
= vfs_path_build_filename (dir
, filename
, (char *) NULL
);
1441 edit_file_at_line (fullname_vpath
, use_internal_edit
!= 0, line
);
1443 view_file_at_line (fullname_vpath
, unparsed_view
, use_internal_view
!= 0, line
,
1444 search_start
, search_end
);
1445 vfs_path_free (fullname_vpath
);
1449 /* --------------------------------------------------------------------------------------------- */
1452 view_edit_currently_selected_file (gboolean unparsed_view
, gboolean edit
)
1455 find_match_location_t
*location
;
1457 listbox_get_current (find_list
, &text
, (void **) &location
);
1459 if ((text
== NULL
) || (location
== NULL
) || (location
->dir
== NULL
))
1460 return MSG_NOT_HANDLED
;
1462 find_do_view_edit (unparsed_view
, edit
, location
->dir
, text
, location
->start
, location
->end
);
1466 /* --------------------------------------------------------------------------------------------- */
1469 find_calc_button_locations (const WDialog
* h
, gboolean all_buttons
)
1471 const int cols
= CONST_WIDGET (h
)->cols
;
1475 l1
= fbuts
[0].len
+ fbuts
[1].len
+ fbuts
[is_start
? 3 : 2].len
+ fbuts
[4].len
+ 3;
1476 l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
+ 2;
1478 fbuts
[0].x
= (cols
- l1
) / 2;
1479 fbuts
[1].x
= fbuts
[0].x
+ fbuts
[0].len
+ 1;
1480 fbuts
[2].x
= fbuts
[1].x
+ fbuts
[1].len
+ 1;
1481 fbuts
[3].x
= fbuts
[2].x
;
1482 fbuts
[4].x
= fbuts
[2].x
+ fbuts
[is_start
? 3 : 2].len
+ 1;
1486 fbuts
[5].x
= (cols
- l2
) / 2;
1487 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ 1;
1488 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ 1;
1492 /* --------------------------------------------------------------------------------------------- */
1495 find_relocate_buttons (const WDialog
* h
, gboolean all_buttons
)
1499 find_calc_button_locations (h
, all_buttons
);
1501 for (i
= 0; i
< fbuts_num
; i
++)
1502 fbuts
[i
].button
->x
= CONST_WIDGET (h
)->x
+ fbuts
[i
].x
;
1505 /* --------------------------------------------------------------------------------------------- */
1508 find_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1510 WDialog
*h
= DIALOG (w
);
1515 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1517 gboolean unparsed_view
= (parm
== KEY_F (13));
1519 return view_edit_currently_selected_file (unparsed_view
, FALSE
);
1521 if (parm
== KEY_F (4))
1522 return view_edit_currently_selected_file (FALSE
, TRUE
);
1523 return MSG_NOT_HANDLED
;
1526 dlg_set_size (h
, LINES
- 4, COLS
- 16);
1527 find_relocate_buttons (h
, TRUE
);
1535 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
1539 /* --------------------------------------------------------------------------------------------- */
1540 /** Handles the Stop/Start button in the find window */
1543 start_stop (WButton
* button
, int action
)
1545 Widget
*w
= WIDGET (button
);
1550 widget_idle (WIDGET (find_dlg
), running
);
1551 is_start
= !is_start
;
1553 status_update (is_start
? _("Stopped") : _("Searching"));
1554 button_set_text (button
, fbuts
[is_start
? 3 : 2].text
);
1556 find_relocate_buttons (w
->owner
, FALSE
);
1557 dlg_redraw (w
->owner
);
1562 /* --------------------------------------------------------------------------------------------- */
1563 /** Handle view command, when invoked as a button */
1566 find_do_view_file (WButton
* button
, int action
)
1571 view_edit_currently_selected_file (FALSE
, FALSE
);
1575 /* --------------------------------------------------------------------------------------------- */
1576 /** Handle edit command, when invoked as a button */
1579 find_do_edit_file (WButton
* button
, int action
)
1584 view_edit_currently_selected_file (FALSE
, TRUE
);
1588 /* --------------------------------------------------------------------------------------------- */
1597 static gboolean i18n_flag
= FALSE
;
1601 for (i
= 0; i
< fbuts_num
; i
++)
1604 fbuts
[i
].text
= _(fbuts
[i
].text
);
1605 #endif /* ENABLE_NLS */
1606 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1607 if (fbuts
[i
].flags
== DEFPUSH_BUTTON
)
1618 dlg_create (TRUE
, 0, 0, lines
, cols
, dialog_colors
, find_callback
, NULL
, "[Find File]",
1619 _("Find File"), DLG_CENTER
);
1621 find_calc_button_locations (find_dlg
, TRUE
);
1624 find_list
= listbox_new (y
, 2, lines
- 10, cols
- 4, FALSE
, NULL
);
1625 add_widget_autopos (find_dlg
, find_list
, WPOS_KEEP_ALL
, NULL
);
1626 y
+= WIDGET (find_list
)->lines
;
1628 add_widget_autopos (find_dlg
, hline_new (y
++, -1, -1), WPOS_KEEP_BOTTOM
, NULL
);
1630 found_num_label
= label_new (y
++, 4, "");
1631 add_widget_autopos (find_dlg
, found_num_label
, WPOS_KEEP_BOTTOM
, NULL
);
1633 status_label
= label_new (y
++, 4, _("Searching"));
1634 add_widget_autopos (find_dlg
, status_label
, WPOS_KEEP_BOTTOM
, NULL
);
1636 add_widget_autopos (find_dlg
, hline_new (y
++, -1, -1), WPOS_KEEP_BOTTOM
, NULL
);
1638 for (i
= 0; i
< fbuts_num
; i
++)
1641 fbuts
[3].button
= fbuts
[2].button
;
1646 (y
, fbuts
[i
].x
, fbuts
[i
].ret_cmd
, fbuts
[i
].flags
, fbuts
[i
].text
,
1647 fbuts
[i
].callback
));
1648 add_widget_autopos (find_dlg
, fbuts
[i
].button
, WPOS_KEEP_BOTTOM
, NULL
);
1651 if (i
== quit_button
)
1655 dlg_select_widget (find_list
);
1658 /* --------------------------------------------------------------------------------------------- */
1665 search_content_handle
= mc_search_new (content_pattern
, NULL
);
1666 if (search_content_handle
)
1668 search_content_handle
->search_type
=
1669 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1670 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1671 search_content_handle
->whole_words
= options
.content_whole_words
;
1673 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1676 search_file_handle
= mc_search_new (find_pattern
, NULL
);
1677 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1678 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1680 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1682 search_file_handle
->is_entire_line
= options
.file_pattern
;
1686 widget_idle (WIDGET (find_dlg
), TRUE
);
1687 ret
= dlg_run (find_dlg
);
1689 mc_search_free (search_file_handle
);
1690 search_file_handle
= NULL
;
1691 mc_search_free (search_content_handle
);
1692 search_content_handle
= NULL
;
1697 /* --------------------------------------------------------------------------------------------- */
1702 widget_idle (WIDGET (find_dlg
), FALSE
);
1703 dlg_destroy (find_dlg
);
1706 /* --------------------------------------------------------------------------------------------- */
1709 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1710 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1712 int return_value
= 0;
1713 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1717 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1718 find_pattern
= (char *) pattern
;
1720 content_pattern
= NULL
;
1721 if (content
!= NULL
&& str_is_valid_string (content
))
1722 content_pattern
= g_strdup (content
);
1725 parse_ignore_dirs (ignore_dirs
);
1726 push_directory (vfs_path_from_str (start_dir
));
1728 return_value
= run_process ();
1730 /* Clear variables */
1733 get_list_info (&file_tmp
, &dir_tmp
, NULL
, NULL
);
1736 *dirname
= g_strdup (dir_tmp
);
1738 *filename
= g_strdup (file_tmp
);
1740 if (return_value
== B_PANELIZE
&& *filename
)
1742 int link_to_dir
, stale_link
;
1746 dir_list
*list
= ¤t_panel
->dir
;
1749 dir_list_init (list
);
1751 for (i
= 0, entry
= listbox_get_first_link (find_list
); entry
!= NULL
;
1752 i
++, entry
= g_list_next (entry
))
1754 const char *lc_filename
= NULL
;
1755 WLEntry
*le
= LENTRY (entry
->data
);
1756 find_match_location_t
*location
= le
->data
;
1759 if ((le
->text
== NULL
) || (location
== NULL
) || (location
->dir
== NULL
))
1762 if (content_pattern
!= NULL
)
1763 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1765 lc_filename
= le
->text
+ 4;
1767 name
= mc_build_filename (location
->dir
, lc_filename
, (char *) NULL
);
1768 /* skip initial start dir */
1769 if (start_dir_len
< 0)
1773 p
= name
+ (size_t) start_dir_len
;
1774 if (IS_PATH_SEP (*p
))
1778 if (!handle_path (p
, &st
, &link_to_dir
, &stale_link
))
1783 /* Need to grow the *list? */
1784 if (list
->len
== list
->size
&& !dir_list_grow (list
, DIR_LIST_RESIZE_STEP
))
1790 /* don't add files more than once to the panel */
1791 if (content_pattern
!= NULL
&& list
->len
!= 0
1792 && strcmp (list
->list
[list
->len
- 1].fname
, p
) == 0)
1798 if (list
->len
== 0) /* first turn i.e clean old list */
1799 panel_clean_dir (current_panel
);
1800 list
->list
[list
->len
].fnamelen
= strlen (p
);
1801 list
->list
[list
->len
].fname
= g_strndup (p
, list
->list
[list
->len
].fnamelen
);
1802 list
->list
[list
->len
].f
.marked
= 0;
1803 list
->list
[list
->len
].f
.link_to_dir
= link_to_dir
;
1804 list
->list
[list
->len
].f
.stale_link
= stale_link
;
1805 list
->list
[list
->len
].f
.dir_size_computed
= 0;
1806 list
->list
[list
->len
].st
= st
;
1807 list
->list
[list
->len
].sort_key
= NULL
;
1808 list
->list
[list
->len
].second_sort_key
= NULL
;
1811 if ((list
->len
& 15) == 0)
1817 current_panel
->is_panelized
= TRUE
;
1820 if (start_dir_len
< 0)
1823 vfs_path_free (current_panel
->cwd_vpath
);
1824 current_panel
->cwd_vpath
= vfs_path_from_str (PATH_SEP_STR
);
1825 ret
= chdir (PATH_SEP_STR
);
1828 panelize_save_panel (current_panel
);
1832 g_free (content_pattern
);
1834 do_search (NULL
); /* force do_search to release resources */
1835 MC_PTR_FREE (old_dir
);
1836 rotate_dash (FALSE
);
1838 return return_value
;
1841 /* --------------------------------------------------------------------------------------------- */
1842 /*** public functions ****************************************************************************/
1843 /* --------------------------------------------------------------------------------------------- */
1848 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1849 ssize_t start_dir_len
;
1851 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1853 char *filename
= NULL
, *dirname
= NULL
;
1856 if (pattern
[0] != '\0')
1858 last_refresh
.tv_sec
= 0;
1859 last_refresh
.tv_usec
= 0;
1862 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
,
1867 g_free (ignore_dirs
);
1872 if (dirname
!= NULL
)
1874 vfs_path_t
*dirname_vpath
;
1876 dirname_vpath
= vfs_path_from_str (dirname
);
1877 do_cd (dirname_vpath
, cd_exact
);
1878 vfs_path_free (dirname_vpath
);
1879 if (filename
!= NULL
)
1880 try_to_select (current_panel
,
1881 filename
+ (content
!= NULL
1882 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1884 else if (filename
!= NULL
)
1886 vfs_path_t
*filename_vpath
;
1888 filename_vpath
= vfs_path_from_str (filename
);
1889 do_cd (filename_vpath
, cd_exact
);
1890 vfs_path_free (filename_vpath
);
1898 if (v
== B_ENTER
|| v
== B_CANCEL
)
1901 if (v
== B_PANELIZE
)
1903 panel_re_sort (current_panel
);
1904 try_to_select (current_panel
, NULL
);
1910 /* --------------------------------------------------------------------------------------------- */