2 Find file command for the Midnight Commander
4 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
6 The Free Software Foundation, Inc.
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * \brief Source: Find file command
40 #include "lib/global.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/key.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" /* canonicalize_pathname() */
52 #include "src/setup.h" /* verbose */
53 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
56 #include "cmd.h" /* view_file_at_line */
57 #include "midnight.h" /* current_panel */
63 /*** global variables ****************************************************************************/
65 /*** file scope macro definitions ****************************************************************/
67 /* Size of the find window */
68 #define FIND2_Y (LINES - 4)
70 #define FIND2_X_USE (FIND2_X - 20)
72 /*** file scope type declarations ****************************************************************/
74 /* A couple of extra messages we need */
91 /* find file options */
94 /* file name options */
95 gboolean file_case_sens
;
96 gboolean file_pattern
;
99 gboolean file_all_charsets
;
101 /* file content options */
102 gboolean content_use
;
103 gboolean content_case_sens
;
104 gboolean content_regexp
;
105 gboolean content_first_hit
;
106 gboolean content_whole_words
;
107 gboolean content_all_charsets
;
109 /* whether use ignore dirs or not */
110 gboolean ignore_dirs_enable
;
111 /* list of directories to be ignored, separated by ':' */
113 } find_file_options_t
;
115 /*** file scope variables ************************************************************************/
117 /* Parsed ignore dirs */
118 static char **find_ignore_dirs
= NULL
;
120 /* Size of the find parameters window */
122 static int FIND_Y
= 19;
124 static int FIND_Y
= 18;
126 static int FIND_X
= 68;
128 static int FIND2_X
= 64;
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_use_cbox
; /* Take into account the Content field */
141 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
142 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
143 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
144 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
146 static WCheck
*file_all_charsets_cbox
;
147 static WCheck
*content_all_charsets_cbox
;
149 static WCheck
*ignore_dirs_cbox
;
151 static gboolean running
= FALSE
; /* nice flag */
152 static char *find_pattern
= NULL
; /* Pattern to search */
153 static char *content_pattern
= NULL
; /* pattern to search inside files; if
154 content_regexp_flag is true, it contains the
155 regex pattern, else the search string. */
156 static unsigned long matches
; /* Number of matches */
157 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
158 static char *old_dir
= NULL
;
160 /* Where did we stop */
162 static int last_line
;
165 static size_t ignore_count
= 0;
167 static Dlg_head
*find_dlg
; /* The dialog */
168 static WButton
*stop_button
; /* pointer to the stop button */
169 static WLabel
*status_label
; /* Finished, Searching etc. */
170 static WLabel
*found_num_label
; /* Number of found items */
171 static WListbox
*find_list
; /* Listbox with the file list */
173 /* This keeps track of the directory stack */
174 #if GLIB_CHECK_VERSION (2, 14, 0)
175 static GQueue dir_queue
= G_QUEUE_INIT
;
177 typedef struct dir_stack
180 struct dir_stack
*prev
;
183 static dir_stack
*dir_stack_base
= 0;
184 #endif /* GLIB_CHECK_VERSION */
190 int len
; /* length including space and brackets */
194 {N_("&Suspend"), 11, 29},
195 {N_("Con&tinue"), 12, 29},
196 {N_("&Chdir"), 11, 3},
197 {N_("&Again"), 9, 17},
198 {N_("&Quit"), 8, 43},
199 {N_("Pane&lize"), 12, 3},
200 {N_("&View - F3"), 13, 20},
201 {N_("&Edit - F4"), 13, 38}
205 static find_file_options_t options
= {
206 TRUE
, TRUE
, TRUE
, FALSE
, FALSE
,
207 FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
210 static char *in_start_dir
= INPUT_LAST_TEXT
;
212 static mc_search_t
*search_file_handle
= NULL
;
213 static mc_search_t
*search_content_handle
= NULL
;
215 /*** file scope functions ************************************************************************/
218 parse_ignore_dirs (const char *ignore_dirs
)
220 size_t r
= 0, w
= 0; /* read and write iterators */
222 if (!options
.ignore_dirs_enable
|| ignore_dirs
== NULL
|| ignore_dirs
[0] == '\0')
225 find_ignore_dirs
= g_strsplit (ignore_dirs
, ":", -1);
227 /* Values like '/foo::/bar: produce holes in list.
228 * Find and remove them */
229 for (; find_ignore_dirs
[r
] != NULL
; r
++)
231 if (find_ignore_dirs
[r
][0] == '\0')
233 /* empty entry -- skip it */
234 g_free (find_ignore_dirs
[r
]);
235 find_ignore_dirs
[r
] = NULL
;
241 /* copy entry to the previous free array cell */
242 find_ignore_dirs
[w
] = find_ignore_dirs
[r
];
243 find_ignore_dirs
[r
] = NULL
;
246 canonicalize_pathname (find_ignore_dirs
[w
]);
247 if (find_ignore_dirs
[w
][0] != '\0')
251 g_free (find_ignore_dirs
[w
]);
252 find_ignore_dirs
[w
] = NULL
;
256 if (find_ignore_dirs
[0] == NULL
)
258 g_strfreev (find_ignore_dirs
);
259 find_ignore_dirs
= NULL
;
263 /* --------------------------------------------------------------------------------------------- */
266 find_load_options (void)
268 static gboolean loaded
= FALSE
;
275 options
.file_case_sens
=
276 mc_config_get_bool (mc_main_config
, "FindFile", "file_case_sens", TRUE
);
277 options
.file_pattern
=
278 mc_config_get_bool (mc_main_config
, "FindFile", "file_shell_pattern", TRUE
);
279 options
.find_recurs
= mc_config_get_bool (mc_main_config
, "FindFile", "file_find_recurs", TRUE
);
280 options
.skip_hidden
=
281 mc_config_get_bool (mc_main_config
, "FindFile", "file_skip_hidden", FALSE
);
282 options
.file_all_charsets
=
283 mc_config_get_bool (mc_main_config
, "FindFile", "file_all_charsets", FALSE
);
284 options
.content_use
= mc_config_get_bool (mc_main_config
, "FindFile", "content_use", TRUE
);
285 options
.content_case_sens
=
286 mc_config_get_bool (mc_main_config
, "FindFile", "content_case_sens", TRUE
);
287 options
.content_regexp
=
288 mc_config_get_bool (mc_main_config
, "FindFile", "content_regexp", FALSE
);
289 options
.content_first_hit
=
290 mc_config_get_bool (mc_main_config
, "FindFile", "content_first_hit", FALSE
);
291 options
.content_whole_words
=
292 mc_config_get_bool (mc_main_config
, "FindFile", "content_whole_words", FALSE
);
293 options
.content_all_charsets
=
294 mc_config_get_bool (mc_main_config
, "FindFile", "content_all_charsets", FALSE
);
295 options
.ignore_dirs_enable
=
296 mc_config_get_bool (mc_main_config
, "FindFile", "ignore_dirs_enable", TRUE
);
297 options
.ignore_dirs
= mc_config_get_string (mc_main_config
, "FindFile", "ignore_dirs", "");
299 if (options
.ignore_dirs
[0] == '\0')
301 g_free (options
.ignore_dirs
);
302 options
.ignore_dirs
= NULL
;
306 /* --------------------------------------------------------------------------------------------- */
309 find_save_options (void)
311 mc_config_set_bool (mc_main_config
, "FindFile", "file_case_sens", options
.file_case_sens
);
312 mc_config_set_bool (mc_main_config
, "FindFile", "file_shell_pattern", options
.file_pattern
);
313 mc_config_set_bool (mc_main_config
, "FindFile", "file_find_recurs", options
.find_recurs
);
314 mc_config_set_bool (mc_main_config
, "FindFile", "file_skip_hidden", options
.skip_hidden
);
315 mc_config_set_bool (mc_main_config
, "FindFile", "file_all_charsets", options
.file_all_charsets
);
316 mc_config_set_bool (mc_main_config
, "FindFile", "content_use", options
.content_use
);
317 mc_config_set_bool (mc_main_config
, "FindFile", "content_case_sens", options
.content_case_sens
);
318 mc_config_set_bool (mc_main_config
, "FindFile", "content_regexp", options
.content_regexp
);
319 mc_config_set_bool (mc_main_config
, "FindFile", "content_first_hit", options
.content_first_hit
);
320 mc_config_set_bool (mc_main_config
, "FindFile", "content_whole_words",
321 options
.content_whole_words
);
322 mc_config_set_bool (mc_main_config
, "FindFile", "content_all_charsets",
323 options
.content_all_charsets
);
324 mc_config_set_bool (mc_main_config
, "FindFile", "ignore_dirs_enable",
325 options
.ignore_dirs_enable
);
326 mc_config_set_string (mc_main_config
, "FindFile", "ignore_dirs", options
.ignore_dirs
);
329 /* --------------------------------------------------------------------------------------------- */
332 add_to_list (const char *text
, void *data
)
334 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
);
337 /* --------------------------------------------------------------------------------------------- */
340 stop_idle (void *data
)
342 set_idle_proc (data
, 0);
345 /* --------------------------------------------------------------------------------------------- */
348 status_update (const char *text
)
350 label_set_text (status_label
, text
);
353 /* --------------------------------------------------------------------------------------------- */
356 found_num_update (void)
358 char buffer
[BUF_TINY
];
359 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
360 label_set_text (found_num_label
, buffer
);
363 /* --------------------------------------------------------------------------------------------- */
366 get_list_info (char **file
, char **dir
)
368 listbox_get_current (find_list
, file
, (void **) dir
);
371 /* --------------------------------------------------------------------------------------------- */
372 /** check regular expression */
375 find_check_regexp (const char *r
)
378 gboolean regexp_ok
= FALSE
;
380 search
= mc_search_new (r
, -1);
384 search
->search_type
= MC_SEARCH_T_REGEX
;
385 regexp_ok
= mc_search_prepare (search
);
386 mc_search_free (search
);
392 /* --------------------------------------------------------------------------------------------- */
394 * Callback for the parameter dialog.
395 * Validate regex, prevent closing the dialog if it's invalid.
399 find_parm_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
404 if (sender
== WIDGET (content_use_cbox
))
406 gboolean disable
= !(content_use_cbox
->state
& C_BOOL
);
408 widget_disable (WIDGET (in_with
), disable
);
409 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
410 widget_disable (WIDGET (content_regexp_cbox
), disable
);
411 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
413 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
415 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
420 if (sender
== WIDGET (ignore_dirs_cbox
))
422 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
424 widget_disable (WIDGET (in_ignore
), disable
);
429 return MSG_NOT_HANDLED
;
433 if (h
->ret_value
!= B_ENTER
)
436 /* check filename regexp */
437 if (!(file_pattern_cbox
->state
& C_BOOL
)
438 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->buffer
))
440 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
441 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
442 dlg_select_widget (in_name
);
446 /* check content regexp */
447 if ((content_use_cbox
->state
& C_BOOL
) && (content_regexp_cbox
->state
& C_BOOL
)
448 && (in_with
->buffer
[0] != '\0') && !find_check_regexp (in_with
->buffer
))
450 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
451 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
452 dlg_select_widget (in_with
);
459 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
463 /* --------------------------------------------------------------------------------------------- */
465 * find_parameters: gets information from the user
467 * If the return value is TRUE, then the following holds:
469 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
470 * They are newly allocated strings and must be freed when uneeded.
472 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
473 * of start_dir (which is absolute). It is used to get a relative pats of find results.
477 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
478 char **ignore_dirs
, char **pattern
, char **content
)
480 gboolean return_value
;
483 const char *file_case_label
= N_("Cas&e sensitive");
484 const char *file_pattern_label
= N_("&Using shell patterns");
485 const char *file_recurs_label
= N_("&Find recursively");
486 const char *file_skip_hidden_label
= N_("S&kip hidden");
488 const char *file_all_charsets_label
= N_("&All charsets");
492 const char *content_use_label
= N_("Sea&rch for content");
493 const char *content_case_label
= N_("Case sens&itive");
494 const char *content_regexp_label
= N_("Re&gular expression");
495 const char *content_first_hit_label
= N_("Fir&st hit");
496 const char *content_whole_words_label
= N_("&Whole words");
498 const char *content_all_charsets_label
= N_("A&ll charsets");
501 const char *buts
[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
510 int i
= sizeof (buts
) / sizeof (buts
[0]);
512 buts
[i
] = _(buts
[i
]);
514 file_case_label
= _(file_case_label
);
515 file_pattern_label
= _(file_pattern_label
);
516 file_recurs_label
= _(file_recurs_label
);
517 file_skip_hidden_label
= _(file_skip_hidden_label
);
519 file_all_charsets_label
= _(file_all_charsets_label
);
520 content_all_charsets_label
= _(content_all_charsets_label
);
522 content_use_label
= _(content_use_label
);
523 content_case_label
= _(content_case_label
);
524 content_regexp_label
= _(content_regexp_label
);
525 content_first_hit_label
= _(content_first_hit_label
);
526 content_whole_words_label
= _(content_whole_words_label
);
528 #endif /* ENABLE_NLS */
530 b0
= str_term_width1 (buts
[0]) + 6; /* default button */
531 b1
= str_term_width1 (buts
[1]) + 4;
532 b2
= str_term_width1 (buts
[2]) + 4;
534 find_load_options ();
536 if (in_start_dir
== NULL
)
537 in_start_dir
= g_strdup (".");
539 disable
= !options
.content_use
;
542 create_dlg (TRUE
, 0, 0, FIND_Y
, FIND_X
, dialog_colors
,
543 find_parm_callback
, NULL
, "[Find File]", _("Find File"),
544 DLG_CENTER
| DLG_REVERSE
);
546 add_widget (find_dlg
,
547 button_new (FIND_Y
- 3, FIND_X
* 3 / 4 - b1
/ 2, B_CANCEL
, NORMAL_BUTTON
, buts
[1],
549 add_widget (find_dlg
,
550 button_new (FIND_Y
- 3, FIND_X
/ 4 - b0
/ 2, B_ENTER
, DEFPUSH_BUTTON
, buts
[0], 0));
552 cbox_position
= FIND_Y
- 5;
554 content_first_hit_cbox
=
555 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_first_hit
,
556 content_first_hit_label
);
557 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
558 add_widget (find_dlg
, content_first_hit_cbox
);
560 content_whole_words_cbox
=
561 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_whole_words
,
562 content_whole_words_label
);
563 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
564 add_widget (find_dlg
, content_whole_words_cbox
);
567 content_all_charsets_cbox
= check_new (cbox_position
--, FIND_X
/ 2 + 1,
568 options
.content_all_charsets
,
569 content_all_charsets_label
);
570 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
571 add_widget (find_dlg
, content_all_charsets_cbox
);
574 content_case_sens_cbox
=
575 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_case_sens
, content_case_label
);
576 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
577 add_widget (find_dlg
, content_case_sens_cbox
);
579 content_regexp_cbox
=
580 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_regexp
, content_regexp_label
);
581 widget_disable (WIDGET (content_regexp_cbox
), disable
);
582 add_widget (find_dlg
, content_regexp_cbox
);
584 cbox_position
= FIND_Y
- 6;
586 skip_hidden_cbox
= check_new (cbox_position
--, 3, options
.skip_hidden
, file_skip_hidden_label
);
587 add_widget (find_dlg
, skip_hidden_cbox
);
590 file_all_charsets_cbox
=
591 check_new (cbox_position
--, 3, options
.file_all_charsets
, file_all_charsets_label
);
592 add_widget (find_dlg
, file_all_charsets_cbox
);
595 file_case_sens_cbox
= check_new (cbox_position
--, 3, options
.file_case_sens
, file_case_label
);
596 add_widget (find_dlg
, file_case_sens_cbox
);
598 file_pattern_cbox
= check_new (cbox_position
--, 3, options
.file_pattern
, file_pattern_label
);
599 add_widget (find_dlg
, file_pattern_cbox
);
601 recursively_cbox
= check_new (cbox_position
, 3, options
.find_recurs
, file_recurs_label
);
602 add_widget (find_dlg
, recursively_cbox
);
604 /* This checkbox is located in the second column */
606 check_new (cbox_position
, FIND_X
/ 2 + 1, options
.content_use
, content_use_label
);
607 add_widget (find_dlg
, content_use_cbox
);
610 input_new (8, FIND_X
/ 2 + 1, input_get_default_colors (), FIND_X
/ 2 - 4, INPUT_LAST_TEXT
,
611 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_DEFAULT
);
612 content_label
= label_new (7, FIND_X
/ 2 + 1, _("Content:"));
613 in_with
->label
= content_label
;
614 widget_disable (WIDGET (in_with
), disable
);
615 add_widget (find_dlg
, in_with
);
616 add_widget (find_dlg
, content_label
);
618 in_name
= input_new (8, 3, input_get_default_colors (),
619 FIND_X
/ 2 - 4, INPUT_LAST_TEXT
, "name", INPUT_COMPLETE_DEFAULT
);
620 add_widget (find_dlg
, in_name
);
621 add_widget (find_dlg
, label_new (7, 3, _("File name:")));
623 in_ignore
= input_new (5, 3, input_get_default_colors (), FIND_X
- 6,
624 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "",
625 "ignoredirs", INPUT_COMPLETE_DEFAULT
);
626 widget_disable (WIDGET (in_ignore
), !options
.ignore_dirs_enable
);
627 add_widget (find_dlg
, in_ignore
);
630 check_new (4, 3, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
631 add_widget (find_dlg
, ignore_dirs_cbox
);
633 add_widget (find_dlg
, button_new (3, FIND_X
- b2
- 2, B_TREE
, NORMAL_BUTTON
, buts
[2], 0));
635 in_start
= input_new (3, 3, input_get_default_colors (),
636 FIND_X
- b2
- 6, in_start_dir
, "start", INPUT_COMPLETE_DEFAULT
);
637 add_widget (find_dlg
, in_start
);
638 add_widget (find_dlg
, label_new (2, 3, _("Start at:")));
641 dlg_select_widget (in_name
);
643 switch (run_dlg (find_dlg
))
646 return_value
= FALSE
;
653 temp_dir
= in_start
->buffer
;
654 if ((temp_dir
[0] == '\0') || ((temp_dir
[0] == '.') && (temp_dir
[1] == '\0')))
655 temp_dir
= vfs_path_to_str (current_panel
->cwd_vpath
);
657 temp_dir
= g_strdup (temp_dir
);
659 if (in_start_dir
!= INPUT_LAST_TEXT
)
660 g_free (in_start_dir
);
661 in_start_dir
= tree_box (temp_dir
);
662 if (in_start_dir
== NULL
)
663 in_start_dir
= temp_dir
;
667 input_assign_text (in_start
, in_start_dir
);
669 /* Warning: Dreadful goto */
678 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
679 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
681 options
.content_use
= content_use_cbox
->state
& C_BOOL
;
682 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
683 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
684 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
685 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
686 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
687 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
688 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
689 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
690 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
691 g_free (options
.ignore_dirs
);
692 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
694 *content
= (options
.content_use
&& in_with
->buffer
[0] != '\0')
695 ? g_strdup (in_with
->buffer
) : NULL
;
696 *start_dir
= in_start
->buffer
[0] != '\0' ? in_start
->buffer
: (char *) ".";
697 *pattern
= g_strdup (in_name
->buffer
);
698 if (in_start_dir
!= INPUT_LAST_TEXT
)
699 g_free (in_start_dir
);
700 in_start_dir
= g_strdup (*start_dir
);
702 s
= tilde_expand (*start_dir
);
703 canonicalize_pathname (s
);
705 if (s
[0] == '.' && s
[1] == '\0')
707 *start_dir
= vfs_path_to_str (current_panel
->cwd_vpath
);
708 /* FIXME: is current_panel->cwd_vpath canonicalized? */
709 /* relative paths will be used in panelization */
710 *start_dir_len
= (ssize_t
) strlen (*start_dir
);
713 else if (g_path_is_absolute (s
))
720 /* relative paths will be used in panelization */
723 cwd_str
= vfs_path_to_str (current_panel
->cwd_vpath
);
724 *start_dir
= mc_build_filename (cwd_str
, s
, (char *) NULL
);
725 *start_dir_len
= (ssize_t
) strlen (cwd_str
);
730 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
731 || (in_ignore
->buffer
[0] == '.' && in_ignore
->buffer
[1] == '\0'))
734 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
736 find_save_options ();
742 destroy_dlg (find_dlg
);
747 /* --------------------------------------------------------------------------------------------- */
749 #if GLIB_CHECK_VERSION (2, 14, 0)
751 push_directory (const vfs_path_t
* dir
)
753 g_queue_push_head (&dir_queue
, (void *) dir
);
756 /* --------------------------------------------------------------------------------------------- */
758 static inline vfs_path_t
*
761 return (vfs_path_t
*) g_queue_pop_tail (&dir_queue
);
764 /* --------------------------------------------------------------------------------------------- */
765 /** Remove all the items from the stack */
770 g_queue_foreach (&dir_queue
, (GFunc
) vfs_path_free
, NULL
);
771 g_queue_clear (&dir_queue
);
774 /* --------------------------------------------------------------------------------------------- */
776 #else /* GLIB_CHECK_VERSION */
778 push_directory (const vfs_path_t
* dir
)
782 new = g_new (dir_stack
, 1);
783 new->name
= (vfs_path_t
*) dir
;
784 new->prev
= dir_stack_base
;
785 dir_stack_base
= new;
788 /* --------------------------------------------------------------------------------------------- */
793 vfs_path_t
*name
= NULL
;
795 if (dir_stack_base
!= NULL
)
798 name
= dir_stack_base
->name
;
799 next
= dir_stack_base
->prev
;
800 g_free (dir_stack_base
);
801 dir_stack_base
= next
;
807 /* --------------------------------------------------------------------------------------------- */
808 /** Remove all the items from the stack */
813 vfs_path_t
*dir
= NULL
;
815 while ((dir
= pop_directory ()) != NULL
)
818 #endif /* GLIB_CHECK_VERSION */
820 /* --------------------------------------------------------------------------------------------- */
823 insert_file (const char *dir
, const char *file
)
825 char *tmp_name
= NULL
;
826 static char *dirname
= NULL
;
828 while (dir
[0] == PATH_SEP
&& dir
[1] == PATH_SEP
)
833 if (strcmp (old_dir
, dir
))
836 old_dir
= g_strdup (dir
);
837 dirname
= add_to_list (dir
, NULL
);
842 old_dir
= g_strdup (dir
);
843 dirname
= add_to_list (dir
, NULL
);
846 tmp_name
= g_strdup_printf (" %s", file
);
847 add_to_list (tmp_name
, dirname
);
851 /* --------------------------------------------------------------------------------------------- */
854 find_add_match (const char *dir
, const char *file
)
856 insert_file (dir
, file
);
860 listbox_select_first (find_list
);
861 send_message (WIDGET (find_list
), NULL
, WIDGET_DRAW
, 0, NULL
);
867 /* --------------------------------------------------------------------------------------------- */
871 * Returns malloced null-terminated line from file file_fd.
872 * Input is buffered in buf_size long buffer.
873 * Current pos in buf is stored in pos.
874 * n_read - number of read chars.
875 * has_newline - is there newline ?
879 get_line_at (int file_fd
, char *buf
, int buf_size
, int *pos
, int *n_read
, gboolean
* has_newline
)
891 *n_read
= mc_read (file_fd
, buf
, buf_size
);
899 /* skip possible leading zero(s) */
905 if (i
>= buffer_size
- 1)
906 buffer
= g_realloc (buffer
, buffer_size
+= 80);
915 *has_newline
= (ch
!= '\0');
923 /* --------------------------------------------------------------------------------------------- */
925 static FindProgressStatus
926 check_find_events (Dlg_head
* h
)
932 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
935 dlg_process_event (h
, c
, &event
);
936 if (h
->ret_value
== B_ENTER
937 || h
->ret_value
== B_CANCEL
|| h
->ret_value
== B_AGAIN
|| h
->ret_value
== B_PANELIZE
)
939 /* dialog terminated */
942 if (!(h
->flags
& DLG_WANT_IDLE
))
944 /* searching suspended */
952 /* --------------------------------------------------------------------------------------------- */
956 * Search the content_pattern string in the DIRECTORY/FILE.
957 * It will add the found entries to the find listbox.
959 * returns FALSE if do_search should look for another file
960 * TRUE if do_search should exit and proceed to the event handler
964 search_content (Dlg_head
* h
, const char *directory
, const char *filename
)
969 gboolean ret_val
= FALSE
;
972 vpath
= vfs_path_build_filename (directory
, filename
, (char *) NULL
);
974 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
976 vfs_path_free (vpath
);
980 file_fd
= mc_open (vpath
, O_RDONLY
);
981 vfs_path_free (vpath
);
986 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), str_trunc (filename
, FIND2_X_USE
));
988 status_update (buffer
);
991 tty_enable_interrupt_key ();
992 tty_got_interrupt ();
998 gboolean has_newline
;
1000 gboolean found
= FALSE
;
1002 char result
[BUF_MEDIUM
];
1006 /* We've been previously suspended, start from the previous position */
1012 && (p
= get_line_at (file_fd
, buffer
, sizeof (buffer
),
1013 &pos
, &n_read
, &has_newline
)) != NULL
)
1015 if (!found
/* Search in binary line once */
1016 && mc_search_run (search_content_handle
,
1017 (const void *) p
, 0, strlen (p
), &found_len
))
1019 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1020 find_add_match (directory
, result
);
1025 if (found
&& options
.content_first_hit
)
1034 if ((line
& 0xff) == 0)
1036 FindProgressStatus res
;
1037 res
= check_find_events (h
);
1056 tty_disable_interrupt_key ();
1061 /* --------------------------------------------------------------------------------------------- */
1064 If dir is absolute, this means we're within dir and searching file here.
1065 If dir is relative, this means we're going to add dir to the directory stack.
1068 find_ignore_dir_search (const char *dir
)
1070 if (find_ignore_dirs
!= NULL
)
1072 const size_t dlen
= strlen (dir
);
1073 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1077 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1079 const size_t ilen
= strlen (*ignore_dir
);
1080 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1082 /* ignore dir is too long -- skip it */
1086 /* handle absolute and relative paths */
1087 switch (iabs
| dabs
)
1089 case 0: /* both paths are relative */
1090 case 3: /* both paths are abolute */
1091 /* if ignore dir is not a path of dir -- skip it */
1092 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1094 /* be sure that ignore dir is not a part of dir like:
1095 ignore dir is "h", dir is "home" */
1096 if (dir
[ilen
] == '\0' || dir
[ilen
] == PATH_SEP
)
1100 case 1: /* dir is absolute, ignore_dir is relative */
1104 d
= strstr (dir
, *ignore_dir
);
1105 if (d
!= NULL
&& d
[-1] == PATH_SEP
&& (d
[ilen
] == '\0' || d
[ilen
] == PATH_SEP
))
1109 case 2: /* dir is relative, ignore_dir is absolute */
1110 /* FIXME: skip this case */
1112 default: /* this cannot occurs */
1121 /* --------------------------------------------------------------------------------------------- */
1124 find_rotate_dash (const Dlg_head
* h
, gboolean finish
)
1126 static const char rotating_dash
[] = "|/-\\";
1127 static unsigned int pos
= 0;
1131 pos
= (pos
+ 1) % 4;
1132 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1133 widget_move (h
, FIND2_Y
- 7, FIND2_X
- 4);
1134 tty_print_char (finish
? ' ' : rotating_dash
[pos
]);
1139 /* --------------------------------------------------------------------------------------------- */
1142 do_search (Dlg_head
* h
)
1144 static struct dirent
*dp
= NULL
;
1145 static DIR *dirp
= NULL
;
1146 static char *directory
= NULL
;
1147 struct stat tmp_stat
;
1148 static int subdirs_left
= 0;
1150 unsigned short count
;
1153 { /* someone forces me to close dirp */
1165 for (count
= 0; count
< 32; count
++)
1175 while (dirp
== NULL
)
1177 vfs_path_t
*tmp_vpath
= NULL
;
1179 tty_setcolor (REVERSE_COLOR
);
1183 tmp_vpath
= pop_directory ();
1184 if (tmp_vpath
== NULL
)
1187 if (ignore_count
== 0)
1188 status_update (_("Finished"));
1191 char msg
[BUF_SMALL
];
1192 g_snprintf (msg
, sizeof (msg
),
1193 ngettext ("Finished (ignored %zd directory)",
1194 "Finished (ignored %zd directories)",
1195 ignore_count
), ignore_count
);
1196 status_update (msg
);
1198 find_rotate_dash (h
, TRUE
);
1203 /* handle absolute ignore dirs here */
1208 tmp
= vfs_path_to_str (tmp_vpath
);
1209 ok
= find_ignore_dir_search (tmp
);
1215 vfs_path_free (tmp_vpath
);
1220 directory
= vfs_path_to_str (tmp_vpath
);
1224 char buffer
[BUF_SMALL
];
1226 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"),
1227 str_trunc (directory
, FIND2_X_USE
));
1228 status_update (buffer
);
1230 /* mc_stat should not be called after mc_opendir
1231 because vfs_s_opendir modifies the st_nlink
1233 if (mc_stat (tmp_vpath
, &tmp_stat
) == 0)
1234 subdirs_left
= tmp_stat
.st_nlink
- 2;
1238 dirp
= mc_opendir (tmp_vpath
);
1239 vfs_path_free (tmp_vpath
);
1240 } /* while (!dirp) */
1242 /* skip invalid filenames */
1243 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1247 if (strcmp (dp
->d_name
, ".") == 0 || strcmp (dp
->d_name
, "..") == 0)
1249 /* skip invalid filenames */
1250 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1256 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1260 if ((subdirs_left
!= 0) && options
.find_recurs
&& (directory
!= NULL
))
1261 { /* Can directory be NULL ? */
1262 /* handle relative ignore dirs here */
1263 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1267 vfs_path_t
*tmp_vpath
;
1269 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1271 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1273 push_directory (tmp_vpath
);
1277 vfs_path_free (tmp_vpath
);
1281 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1282 0, strlen (dp
->d_name
), &bytes_found
);
1286 if (content_pattern
== NULL
)
1287 find_add_match (directory
, dp
->d_name
);
1288 else if (search_content (h
, directory
, dp
->d_name
))
1293 /* skip invalid filenames */
1294 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1298 find_rotate_dash (h
, FALSE
);
1303 /* --------------------------------------------------------------------------------------------- */
1306 init_find_vars (void)
1313 /* Remove all the items from the stack */
1316 g_strfreev (find_ignore_dirs
);
1317 find_ignore_dirs
= NULL
;
1320 /* --------------------------------------------------------------------------------------------- */
1323 find_do_view_edit (int unparsed_view
, int edit
, char *dir
, char *file
)
1325 char *fullname
= NULL
;
1326 const char *filename
= NULL
;
1328 vfs_path_t
*fullname_vpath
;
1330 if (content_pattern
!= NULL
)
1332 filename
= strchr (file
+ 4, ':') + 1;
1333 line
= atoi (file
+ 4);
1337 filename
= file
+ 4;
1341 fullname_vpath
= vfs_path_build_filename (dir
, filename
, (char *) NULL
);
1343 do_edit_at_line (fullname_vpath
, use_internal_edit
, line
);
1345 view_file_at_line (fullname_vpath
, unparsed_view
, use_internal_view
, line
);
1346 vfs_path_free (fullname_vpath
);
1350 /* --------------------------------------------------------------------------------------------- */
1353 view_edit_currently_selected_file (int unparsed_view
, int edit
)
1358 listbox_get_current (find_list
, &text
, (void **) &dir
);
1360 if ((text
== NULL
) || (dir
== NULL
))
1361 return MSG_NOT_HANDLED
;
1363 find_do_view_edit (unparsed_view
, edit
, dir
, text
);
1367 /* --------------------------------------------------------------------------------------------- */
1370 find_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
1375 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1377 int unparsed_view
= (parm
== KEY_F (13));
1378 return view_edit_currently_selected_file (unparsed_view
, 0);
1380 if (parm
== KEY_F (4))
1382 return view_edit_currently_selected_file (0, 1);
1384 return MSG_NOT_HANDLED
;
1391 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1395 /* --------------------------------------------------------------------------------------------- */
1396 /** Handles the Stop/Start button in the find window */
1399 start_stop (WButton
* button
, int action
)
1405 set_idle_proc (find_dlg
, running
);
1406 is_start
= !is_start
;
1408 status_update (is_start
? _("Stopped") : _("Searching"));
1409 button_set_text (stop_button
, fbuts
[is_start
? 1 : 0].text
);
1414 /* --------------------------------------------------------------------------------------------- */
1415 /** Handle view command, when invoked as a button */
1418 find_do_view_file (WButton
* button
, int action
)
1423 view_edit_currently_selected_file (0, 0);
1427 /* --------------------------------------------------------------------------------------------- */
1428 /** Handle edit command, when invoked as a button */
1431 find_do_edit_file (WButton
* button
, int action
)
1436 view_edit_currently_selected_file (0, 1);
1440 /* --------------------------------------------------------------------------------------------- */
1446 static gboolean i18n_flag
= FALSE
;
1450 int i
= sizeof (fbuts
) / sizeof (fbuts
[0]);
1453 fbuts
[i
].text
= _(fbuts
[i
].text
);
1454 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1457 fbuts
[2].len
+= 2; /* DEFPUSH_BUTTON */
1460 #endif /* ENABLE_NLS */
1463 * Dynamically place buttons centered within current window size
1466 int l0
= max (fbuts
[0].len
, fbuts
[1].len
);
1467 int l1
= fbuts
[2].len
+ fbuts
[3].len
+ l0
+ fbuts
[4].len
;
1468 int l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
;
1471 /* Check, if both button rows fit within FIND2_X */
1472 FIND2_X
= max (l1
+ 9, COLS
- 16);
1473 FIND2_X
= max (l2
+ 8, FIND2_X
);
1475 /* compute amount of space between buttons for each row */
1476 r1
= (FIND2_X
- 4 - l1
) % 5;
1477 l1
= (FIND2_X
- 4 - l1
) / 5;
1478 r2
= (FIND2_X
- 4 - l2
) % 4;
1479 l2
= (FIND2_X
- 4 - l2
) / 4;
1481 /* ...and finally, place buttons */
1482 fbuts
[2].x
= 2 + r1
/ 2 + l1
;
1483 fbuts
[3].x
= fbuts
[2].x
+ fbuts
[2].len
+ l1
;
1484 fbuts
[0].x
= fbuts
[3].x
+ fbuts
[3].len
+ l1
;
1485 fbuts
[4].x
= fbuts
[0].x
+ l0
+ l1
;
1486 fbuts
[5].x
= 2 + r2
/ 2 + l2
;
1487 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ l2
;
1488 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ l2
;
1492 create_dlg (TRUE
, 0, 0, FIND2_Y
, FIND2_X
, dialog_colors
, find_callback
, NULL
,
1493 "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
1495 add_widget (find_dlg
,
1496 button_new (FIND2_Y
- 3, fbuts
[7].x
, B_VIEW
, NORMAL_BUTTON
,
1497 fbuts
[7].text
, find_do_edit_file
));
1498 add_widget (find_dlg
,
1499 button_new (FIND2_Y
- 3, fbuts
[6].x
, B_VIEW
, NORMAL_BUTTON
,
1500 fbuts
[6].text
, find_do_view_file
));
1501 add_widget (find_dlg
,
1502 button_new (FIND2_Y
- 3, fbuts
[5].x
, B_PANELIZE
, NORMAL_BUTTON
, fbuts
[5].text
,
1505 add_widget (find_dlg
,
1506 button_new (FIND2_Y
- 4, fbuts
[4].x
, B_CANCEL
, NORMAL_BUTTON
, fbuts
[4].text
, NULL
));
1508 button_new (FIND2_Y
- 4, fbuts
[0].x
, B_STOP
, NORMAL_BUTTON
, fbuts
[0].text
, start_stop
);
1509 add_widget (find_dlg
, stop_button
);
1510 add_widget (find_dlg
,
1511 button_new (FIND2_Y
- 4, fbuts
[3].x
, B_AGAIN
, NORMAL_BUTTON
, fbuts
[3].text
, NULL
));
1512 add_widget (find_dlg
,
1513 button_new (FIND2_Y
- 4, fbuts
[2].x
, B_ENTER
, DEFPUSH_BUTTON
, fbuts
[2].text
, NULL
));
1515 status_label
= label_new (FIND2_Y
- 7, 4, _("Searching"));
1516 add_widget (find_dlg
, status_label
);
1518 found_num_label
= label_new (FIND2_Y
- 6, 4, "");
1519 add_widget (find_dlg
, found_num_label
);
1521 find_list
= listbox_new (2, 2, FIND2_Y
- 10, FIND2_X
- 4, FALSE
, NULL
);
1522 add_widget (find_dlg
, find_list
);
1525 /* --------------------------------------------------------------------------------------------- */
1532 search_content_handle
= mc_search_new (content_pattern
, -1);
1533 if (search_content_handle
)
1535 search_content_handle
->search_type
=
1536 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1537 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1538 search_content_handle
->whole_words
= options
.content_whole_words
;
1539 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1541 search_file_handle
= mc_search_new (find_pattern
, -1);
1542 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1543 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1544 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1545 search_file_handle
->is_entire_line
= options
.file_pattern
;
1549 set_idle_proc (find_dlg
, 1);
1550 ret
= run_dlg (find_dlg
);
1552 mc_search_free (search_file_handle
);
1553 search_file_handle
= NULL
;
1554 mc_search_free (search_content_handle
);
1555 search_content_handle
= NULL
;
1560 /* --------------------------------------------------------------------------------------------- */
1565 set_idle_proc (find_dlg
, 0);
1566 destroy_dlg (find_dlg
);
1569 /* --------------------------------------------------------------------------------------------- */
1572 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1573 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1575 int return_value
= 0;
1576 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1580 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1581 find_pattern
= (char *) pattern
;
1583 content_pattern
= NULL
;
1584 if (options
.content_use
&& content
!= NULL
&& str_is_valid_string (content
))
1585 content_pattern
= g_strdup (content
);
1588 parse_ignore_dirs (ignore_dirs
);
1589 push_directory (vfs_path_from_str (start_dir
));
1591 return_value
= run_process ();
1593 /* Clear variables */
1596 get_list_info (&file_tmp
, &dir_tmp
);
1599 *dirname
= g_strdup (dir_tmp
);
1601 *filename
= g_strdup (file_tmp
);
1603 if (return_value
== B_PANELIZE
&& *filename
)
1605 int status
, link_to_dir
, stale_link
;
1610 dir_list
*list
= ¤t_panel
->dir
;
1613 if (set_zero_dir (list
))
1616 for (i
= 0, entry
= find_list
->list
; entry
!= NULL
; i
++, entry
= g_list_next (entry
))
1618 const char *lc_filename
= NULL
;
1619 WLEntry
*le
= (WLEntry
*) entry
->data
;
1622 if ((le
->text
== NULL
) || (le
->data
== NULL
))
1625 if (content_pattern
!= NULL
)
1626 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1628 lc_filename
= le
->text
+ 4;
1630 name
= mc_build_filename (le
->data
, lc_filename
, (char *) NULL
);
1631 /* skip initial start dir */
1632 if (start_dir_len
< 0)
1636 p
= name
+ (size_t) start_dir_len
;
1641 status
= handle_path (list
, p
, &st
, next_free
, &link_to_dir
, &stale_link
);
1653 /* don't add files more than once to the panel */
1654 if (content_pattern
!= NULL
&& next_free
> 0
1655 && strcmp (list
->list
[next_free
- 1].fname
, p
) == 0)
1661 if (next_free
== 0) /* first turn i.e clean old list */
1662 panel_clean_dir (current_panel
);
1663 list
->list
[next_free
].fnamelen
= strlen (p
);
1664 list
->list
[next_free
].fname
= g_strndup (p
, list
->list
[next_free
].fnamelen
);
1665 list
->list
[next_free
].f
.marked
= 0;
1666 list
->list
[next_free
].f
.link_to_dir
= link_to_dir
;
1667 list
->list
[next_free
].f
.stale_link
= stale_link
;
1668 list
->list
[next_free
].f
.dir_size_computed
= 0;
1669 list
->list
[next_free
].st
= st
;
1670 list
->list
[next_free
].sort_key
= NULL
;
1671 list
->list
[next_free
].second_sort_key
= NULL
;
1674 if (!(next_free
& 15))
1680 current_panel
->count
= next_free
;
1681 current_panel
->is_panelized
= TRUE
;
1684 if (start_dir_len
< 0)
1687 vfs_path_free (current_panel
->cwd_vpath
);
1688 current_panel
->cwd_vpath
= vfs_path_from_str (PATH_SEP_STR
);
1689 ret
= chdir (PATH_SEP_STR
);
1691 panelize_save_panel (current_panel
);
1695 g_free (content_pattern
);
1697 do_search (NULL
); /* force do_search to release resources */
1701 return return_value
;
1704 /* --------------------------------------------------------------------------------------------- */
1705 /*** public functions ****************************************************************************/
1706 /* --------------------------------------------------------------------------------------------- */
1711 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1712 ssize_t start_dir_len
;
1713 char *filename
= NULL
, *dirname
= NULL
;
1716 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1718 if (pattern
[0] == '\0')
1719 break; /* nothing search */
1721 dirname
= filename
= NULL
;
1723 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
, &filename
);
1724 g_free (ignore_dirs
);
1729 if (dirname
!= NULL
)
1731 vfs_path_t
*dirname_vpath
;
1733 dirname_vpath
= vfs_path_from_str (dirname
);
1734 do_cd (dirname_vpath
, cd_exact
);
1735 vfs_path_free (dirname_vpath
);
1736 if (filename
!= NULL
)
1737 try_to_select (current_panel
,
1738 filename
+ (content
!= NULL
1739 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1741 else if (filename
!= NULL
)
1743 vfs_path_t
*filename_vpath
;
1745 filename_vpath
= vfs_path_from_str (filename
);
1746 do_cd (filename_vpath
, cd_exact
);
1747 vfs_path_free (filename_vpath
);
1762 if (v
== B_PANELIZE
)
1764 panel_re_sort (current_panel
);
1765 try_to_select (current_panel
, NULL
);
1771 /* --------------------------------------------------------------------------------------------- */