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 */
54 #include "src/main.h" /* do_cd */
57 #include "cmd.h" /* view_file_at_line */
58 #include "midnight.h" /* current_panel */
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 /* Size of the find window */
69 #define FIND2_Y (LINES - 4)
71 #define FIND2_X_USE (FIND2_X - 20)
73 /*** file scope type declarations ****************************************************************/
75 /* A couple of extra messages we need */
92 /* find file options */
95 /* file name options */
96 gboolean file_case_sens
;
97 gboolean file_pattern
;
100 gboolean file_all_charsets
;
102 /* file content options */
103 gboolean content_use
;
104 gboolean content_case_sens
;
105 gboolean content_regexp
;
106 gboolean content_first_hit
;
107 gboolean content_whole_words
;
108 gboolean content_all_charsets
;
110 /* whether use ignore dirs or not */
111 gboolean ignore_dirs_enable
;
112 /* list of directories to be ignored, separated by ':' */
114 } find_file_options_t
;
116 /*** file scope variables ************************************************************************/
118 /* Parsed ignore dirs */
119 static char **find_ignore_dirs
= NULL
;
121 /* Size of the find parameters window */
123 static int FIND_Y
= 19;
125 static int FIND_Y
= 18;
127 static int FIND_X
= 68;
129 static int FIND2_X
= 64;
131 /* static variables to remember find parameters */
132 static WInput
*in_start
; /* Start path */
133 static WInput
*in_name
; /* Filename */
134 static WInput
*in_with
; /* Text */
135 static WInput
*in_ignore
;
136 static WLabel
*content_label
; /* 'Content:' label */
137 static WCheck
*file_case_sens_cbox
; /* "case sensitive" checkbox */
138 static WCheck
*file_pattern_cbox
; /* File name is glob or regexp */
139 static WCheck
*recursively_cbox
;
140 static WCheck
*skip_hidden_cbox
;
141 static WCheck
*content_use_cbox
; /* Take into account the Content field */
142 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
143 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
144 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
145 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
147 static WCheck
*file_all_charsets_cbox
;
148 static WCheck
*content_all_charsets_cbox
;
150 static WCheck
*ignore_dirs_cbox
;
152 static gboolean running
= FALSE
; /* nice flag */
153 static char *find_pattern
= NULL
; /* Pattern to search */
154 static char *content_pattern
= NULL
; /* pattern to search inside files; if
155 content_regexp_flag is true, it contains the
156 regex pattern, else the search string. */
157 static unsigned long matches
; /* Number of matches */
158 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
159 static char *old_dir
= NULL
;
161 /* Where did we stop */
163 static int last_line
;
166 static size_t ignore_count
= 0;
168 static Dlg_head
*find_dlg
; /* The dialog */
169 static WButton
*stop_button
; /* pointer to the stop button */
170 static WLabel
*status_label
; /* Finished, Searching etc. */
171 static WLabel
*found_num_label
; /* Number of found items */
172 static WListbox
*find_list
; /* Listbox with the file list */
174 /* This keeps track of the directory stack */
175 #if GLIB_CHECK_VERSION (2, 14, 0)
176 static GQueue dir_queue
= G_QUEUE_INIT
;
178 typedef struct dir_stack
181 struct dir_stack
*prev
;
184 static dir_stack
*dir_stack_base
= 0;
185 #endif /* GLIB_CHECK_VERSION */
191 int len
; /* length including space and brackets */
195 {N_("&Suspend"), 11, 29},
196 {N_("Con&tinue"), 12, 29},
197 {N_("&Chdir"), 11, 3},
198 {N_("&Again"), 9, 17},
199 {N_("&Quit"), 8, 43},
200 {N_("Pane&lize"), 12, 3},
201 {N_("&View - F3"), 13, 20},
202 {N_("&Edit - F4"), 13, 38}
206 static find_file_options_t options
= {
207 TRUE
, TRUE
, TRUE
, FALSE
, FALSE
,
208 FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
211 static char *in_start_dir
= INPUT_LAST_TEXT
;
213 static mc_search_t
*search_file_handle
= NULL
;
214 static mc_search_t
*search_content_handle
= NULL
;
216 /*** file scope functions ************************************************************************/
219 parse_ignore_dirs (const char *ignore_dirs
)
221 size_t r
= 0, w
= 0; /* read and write iterators */
223 if (!options
.ignore_dirs_enable
|| ignore_dirs
== NULL
|| ignore_dirs
[0] == '\0')
226 find_ignore_dirs
= g_strsplit (ignore_dirs
, ":", -1);
228 /* Values like '/foo::/bar: produce holes in list.
229 * Find and remove them */
230 for (; find_ignore_dirs
[r
] != NULL
; r
++)
232 if (find_ignore_dirs
[r
][0] == '\0')
234 /* empty entry -- skip it */
235 g_free (find_ignore_dirs
[r
]);
236 find_ignore_dirs
[r
] = NULL
;
242 /* copy entry to the previous free array cell */
243 find_ignore_dirs
[w
] = find_ignore_dirs
[r
];
244 find_ignore_dirs
[r
] = NULL
;
247 canonicalize_pathname (find_ignore_dirs
[w
]);
248 if (find_ignore_dirs
[w
][0] != '\0')
252 g_free (find_ignore_dirs
[w
]);
253 find_ignore_dirs
[w
] = NULL
;
257 if (find_ignore_dirs
[0] == NULL
)
259 g_strfreev (find_ignore_dirs
);
260 find_ignore_dirs
= NULL
;
264 /* --------------------------------------------------------------------------------------------- */
267 find_load_options (void)
269 static gboolean loaded
= FALSE
;
276 options
.file_case_sens
=
277 mc_config_get_bool (mc_main_config
, "FindFile", "file_case_sens", TRUE
);
278 options
.file_pattern
=
279 mc_config_get_bool (mc_main_config
, "FindFile", "file_shell_pattern", TRUE
);
280 options
.find_recurs
= mc_config_get_bool (mc_main_config
, "FindFile", "file_find_recurs", TRUE
);
281 options
.skip_hidden
=
282 mc_config_get_bool (mc_main_config
, "FindFile", "file_skip_hidden", FALSE
);
283 options
.file_all_charsets
=
284 mc_config_get_bool (mc_main_config
, "FindFile", "file_all_charsets", FALSE
);
285 options
.content_use
= mc_config_get_bool (mc_main_config
, "FindFile", "content_use", TRUE
);
286 options
.content_case_sens
=
287 mc_config_get_bool (mc_main_config
, "FindFile", "content_case_sens", TRUE
);
288 options
.content_regexp
=
289 mc_config_get_bool (mc_main_config
, "FindFile", "content_regexp", FALSE
);
290 options
.content_first_hit
=
291 mc_config_get_bool (mc_main_config
, "FindFile", "content_first_hit", FALSE
);
292 options
.content_whole_words
=
293 mc_config_get_bool (mc_main_config
, "FindFile", "content_whole_words", FALSE
);
294 options
.content_all_charsets
=
295 mc_config_get_bool (mc_main_config
, "FindFile", "content_all_charsets", FALSE
);
296 options
.ignore_dirs_enable
=
297 mc_config_get_bool (mc_main_config
, "FindFile", "ignore_dirs_enable", TRUE
);
298 options
.ignore_dirs
= mc_config_get_string (mc_main_config
, "FindFile", "ignore_dirs", "");
300 if (options
.ignore_dirs
[0] == '\0')
302 g_free (options
.ignore_dirs
);
303 options
.ignore_dirs
= NULL
;
307 /* --------------------------------------------------------------------------------------------- */
310 find_save_options (void)
312 mc_config_set_bool (mc_main_config
, "FindFile", "file_case_sens", options
.file_case_sens
);
313 mc_config_set_bool (mc_main_config
, "FindFile", "file_shell_pattern", options
.file_pattern
);
314 mc_config_set_bool (mc_main_config
, "FindFile", "file_find_recurs", options
.find_recurs
);
315 mc_config_set_bool (mc_main_config
, "FindFile", "file_skip_hidden", options
.skip_hidden
);
316 mc_config_set_bool (mc_main_config
, "FindFile", "file_all_charsets", options
.file_all_charsets
);
317 mc_config_set_bool (mc_main_config
, "FindFile", "content_use", options
.content_use
);
318 mc_config_set_bool (mc_main_config
, "FindFile", "content_case_sens", options
.content_case_sens
);
319 mc_config_set_bool (mc_main_config
, "FindFile", "content_regexp", options
.content_regexp
);
320 mc_config_set_bool (mc_main_config
, "FindFile", "content_first_hit", options
.content_first_hit
);
321 mc_config_set_bool (mc_main_config
, "FindFile", "content_whole_words",
322 options
.content_whole_words
);
323 mc_config_set_bool (mc_main_config
, "FindFile", "content_all_charsets",
324 options
.content_all_charsets
);
325 mc_config_set_bool (mc_main_config
, "FindFile", "ignore_dirs_enable",
326 options
.ignore_dirs_enable
);
327 mc_config_set_string (mc_main_config
, "FindFile", "ignore_dirs", options
.ignore_dirs
);
330 /* --------------------------------------------------------------------------------------------- */
333 add_to_list (const char *text
, void *data
)
335 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
);
338 /* --------------------------------------------------------------------------------------------- */
341 stop_idle (void *data
)
343 set_idle_proc (data
, 0);
346 /* --------------------------------------------------------------------------------------------- */
349 status_update (const char *text
)
351 label_set_text (status_label
, text
);
354 /* --------------------------------------------------------------------------------------------- */
357 found_num_update (void)
359 char buffer
[BUF_TINY
];
360 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
361 label_set_text (found_num_label
, buffer
);
364 /* --------------------------------------------------------------------------------------------- */
367 get_list_info (char **file
, char **dir
)
369 listbox_get_current (find_list
, file
, (void **) dir
);
372 /* --------------------------------------------------------------------------------------------- */
373 /** check regular expression */
376 find_check_regexp (const char *r
)
379 gboolean regexp_ok
= FALSE
;
381 search
= mc_search_new (r
, -1);
385 search
->search_type
= MC_SEARCH_T_REGEX
;
386 regexp_ok
= mc_search_prepare (search
);
387 mc_search_free (search
);
393 /* --------------------------------------------------------------------------------------------- */
395 * Callback for the parameter dialog.
396 * Validate regex, prevent closing the dialog if it's invalid.
400 find_parm_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
405 if (sender
== (Widget
*) content_use_cbox
)
407 gboolean disable
= !(content_use_cbox
->state
& C_BOOL
);
409 widget_disable (content_label
->widget
, disable
);
410 send_message ((Widget
*) content_label
, WIDGET_DRAW
, 0);
411 widget_disable (in_with
->widget
, disable
);
412 send_message ((Widget
*) in_with
, WIDGET_DRAW
, 0);
413 widget_disable (content_first_hit_cbox
->widget
, disable
);
414 send_message ((Widget
*) content_first_hit_cbox
, WIDGET_DRAW
, 0);
415 widget_disable (content_regexp_cbox
->widget
, disable
);
416 send_message ((Widget
*) content_regexp_cbox
, WIDGET_DRAW
, 0);
417 widget_disable (content_case_sens_cbox
->widget
, disable
);
418 send_message ((Widget
*) content_case_sens_cbox
, WIDGET_DRAW
, 0);
420 widget_disable (content_all_charsets_cbox
->widget
, disable
);
421 send_message ((Widget
*) content_all_charsets_cbox
, WIDGET_DRAW
, 0);
423 widget_disable (content_whole_words_cbox
->widget
, disable
);
424 send_message ((Widget
*) content_whole_words_cbox
, WIDGET_DRAW
, 0);
429 if (sender
== (Widget
*) ignore_dirs_cbox
)
431 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
433 widget_disable (in_ignore
->widget
, disable
);
434 send_message ((Widget
*) in_ignore
, WIDGET_DRAW
, 0);
439 return MSG_NOT_HANDLED
;
443 if (h
->ret_value
!= B_ENTER
)
446 /* check filename regexp */
447 if (!(file_pattern_cbox
->state
& C_BOOL
)
448 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->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_name
);
456 /* check content regexp */
457 if ((content_use_cbox
->state
& C_BOOL
) && (content_regexp_cbox
->state
& C_BOOL
)
458 && (in_with
->buffer
[0] != '\0') && !find_check_regexp (in_with
->buffer
))
460 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
461 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
462 dlg_select_widget (in_with
);
469 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
473 /* --------------------------------------------------------------------------------------------- */
475 * find_parameters: gets information from the user
477 * If the return value is TRUE, then the following holds:
479 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
480 * They are newly allocated strings and must be freed when uneeded.
482 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
483 * of start_dir (which is absolute). It is used to get a relative pats of find results.
487 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
488 char **ignore_dirs
, char **pattern
, char **content
)
490 gboolean return_value
;
493 const char *file_case_label
= N_("Cas&e sensitive");
494 const char *file_pattern_label
= N_("&Using shell patterns");
495 const char *file_recurs_label
= N_("&Find recursively");
496 const char *file_skip_hidden_label
= N_("S&kip hidden");
498 const char *file_all_charsets_label
= N_("&All charsets");
502 const char *content_use_label
= N_("Sea&rch for content");
503 const char *content_case_label
= N_("Case sens&itive");
504 const char *content_regexp_label
= N_("Re&gular expression");
505 const char *content_first_hit_label
= N_("Fir&st hit");
506 const char *content_whole_words_label
= N_("&Whole words");
508 const char *content_all_charsets_label
= N_("A&ll charsets");
511 const char *buts
[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
520 int i
= sizeof (buts
) / sizeof (buts
[0]);
522 buts
[i
] = _(buts
[i
]);
524 file_case_label
= _(file_case_label
);
525 file_pattern_label
= _(file_pattern_label
);
526 file_recurs_label
= _(file_recurs_label
);
527 file_skip_hidden_label
= _(file_skip_hidden_label
);
529 file_all_charsets_label
= _(file_all_charsets_label
);
530 content_all_charsets_label
= _(content_all_charsets_label
);
532 content_use_label
= _(content_use_label
);
533 content_case_label
= _(content_case_label
);
534 content_regexp_label
= _(content_regexp_label
);
535 content_first_hit_label
= _(content_first_hit_label
);
536 content_whole_words_label
= _(content_whole_words_label
);
538 #endif /* ENABLE_NLS */
540 b0
= str_term_width1 (buts
[0]) + 6; /* default button */
541 b1
= str_term_width1 (buts
[1]) + 4;
542 b2
= str_term_width1 (buts
[2]) + 4;
544 find_load_options ();
546 if (in_start_dir
== NULL
)
547 in_start_dir
= g_strdup (".");
549 disable
= !options
.content_use
;
552 create_dlg (TRUE
, 0, 0, FIND_Y
, FIND_X
, dialog_colors
,
553 find_parm_callback
, "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
555 add_widget (find_dlg
,
556 button_new (FIND_Y
- 3, FIND_X
* 3 / 4 - b1
/ 2, B_CANCEL
, NORMAL_BUTTON
, buts
[1],
558 add_widget (find_dlg
,
559 button_new (FIND_Y
- 3, FIND_X
/ 4 - b0
/ 2, B_ENTER
, DEFPUSH_BUTTON
, buts
[0], 0));
561 cbox_position
= FIND_Y
- 5;
563 content_first_hit_cbox
=
564 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_first_hit
,
565 content_first_hit_label
);
566 widget_disable (content_first_hit_cbox
->widget
, disable
);
567 add_widget (find_dlg
, content_first_hit_cbox
);
569 content_whole_words_cbox
=
570 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_whole_words
,
571 content_whole_words_label
);
572 widget_disable (content_whole_words_cbox
->widget
, disable
);
573 add_widget (find_dlg
, content_whole_words_cbox
);
576 content_all_charsets_cbox
= check_new (cbox_position
--, FIND_X
/ 2 + 1,
577 options
.content_all_charsets
,
578 content_all_charsets_label
);
579 widget_disable (content_all_charsets_cbox
->widget
, disable
);
580 add_widget (find_dlg
, content_all_charsets_cbox
);
583 content_case_sens_cbox
=
584 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_case_sens
, content_case_label
);
585 widget_disable (content_case_sens_cbox
->widget
, disable
);
586 add_widget (find_dlg
, content_case_sens_cbox
);
588 content_regexp_cbox
=
589 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_regexp
, content_regexp_label
);
590 widget_disable (content_regexp_cbox
->widget
, disable
);
591 add_widget (find_dlg
, content_regexp_cbox
);
593 cbox_position
= FIND_Y
- 6;
595 skip_hidden_cbox
= check_new (cbox_position
--, 3, options
.skip_hidden
, file_skip_hidden_label
);
596 add_widget (find_dlg
, skip_hidden_cbox
);
599 file_all_charsets_cbox
=
600 check_new (cbox_position
--, 3, options
.file_all_charsets
, file_all_charsets_label
);
601 add_widget (find_dlg
, file_all_charsets_cbox
);
604 file_case_sens_cbox
= check_new (cbox_position
--, 3, options
.file_case_sens
, file_case_label
);
605 add_widget (find_dlg
, file_case_sens_cbox
);
607 file_pattern_cbox
= check_new (cbox_position
--, 3, options
.file_pattern
, file_pattern_label
);
608 add_widget (find_dlg
, file_pattern_cbox
);
610 recursively_cbox
= check_new (cbox_position
, 3, options
.find_recurs
, file_recurs_label
);
611 add_widget (find_dlg
, recursively_cbox
);
613 /* This checkbox is located in the second column */
615 check_new (cbox_position
, FIND_X
/ 2 + 1, options
.content_use
, content_use_label
);
616 add_widget (find_dlg
, content_use_cbox
);
619 input_new (8, FIND_X
/ 2 + 1, input_get_default_colors (), FIND_X
/ 2 - 4, INPUT_LAST_TEXT
,
620 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_DEFAULT
);
621 widget_disable (in_with
->widget
, disable
);
622 add_widget (find_dlg
, in_with
);
624 content_label
= label_new (7, FIND_X
/ 2 + 1, _("Content:"));
625 widget_disable (content_label
->widget
, disable
);
626 add_widget (find_dlg
, content_label
);
628 in_name
= input_new (8, 3, input_get_default_colors (),
629 FIND_X
/ 2 - 4, INPUT_LAST_TEXT
, "name", INPUT_COMPLETE_DEFAULT
);
630 add_widget (find_dlg
, in_name
);
631 add_widget (find_dlg
, label_new (7, 3, _("File name:")));
633 in_ignore
= input_new (5, 3, input_get_default_colors (), FIND_X
- 6,
634 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "",
635 "ignoredirs", INPUT_COMPLETE_DEFAULT
);
636 widget_disable (in_ignore
->widget
, !options
.ignore_dirs_enable
);
637 add_widget (find_dlg
, in_ignore
);
640 check_new (4, 3, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
641 add_widget (find_dlg
, ignore_dirs_cbox
);
643 add_widget (find_dlg
, button_new (3, FIND_X
- b2
- 2, B_TREE
, NORMAL_BUTTON
, buts
[2], 0));
645 in_start
= input_new (3, 3, input_get_default_colors (),
646 FIND_X
- b2
- 6, in_start_dir
, "start", INPUT_COMPLETE_DEFAULT
);
647 add_widget (find_dlg
, in_start
);
648 add_widget (find_dlg
, label_new (2, 3, _("Start at:")));
651 dlg_select_widget (in_name
);
653 switch (run_dlg (find_dlg
))
656 return_value
= FALSE
;
661 const char *temp_dir
= in_start
->buffer
;
663 if ((temp_dir
[0] == '\0') || ((temp_dir
[0] == '.') && (temp_dir
[1] == '\0')))
664 temp_dir
= current_panel
->cwd
;
666 if (in_start_dir
!= INPUT_LAST_TEXT
)
667 g_free (in_start_dir
);
668 in_start_dir
= tree_box (temp_dir
);
669 if (in_start_dir
== NULL
)
670 in_start_dir
= g_strdup (temp_dir
);
672 input_assign_text (in_start
, in_start_dir
);
674 /* Warning: Dreadful goto */
683 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
684 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
686 options
.content_use
= content_use_cbox
->state
& C_BOOL
;
687 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
688 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
689 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
690 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
691 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
692 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
693 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
694 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
695 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
696 g_free (options
.ignore_dirs
);
697 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
699 *content
= (options
.content_use
&& in_with
->buffer
[0] != '\0')
700 ? g_strdup (in_with
->buffer
) : NULL
;
701 *start_dir
= in_start
->buffer
[0] != '\0' ? in_start
->buffer
: (char *) ".";
702 *pattern
= g_strdup (in_name
->buffer
);
703 if (in_start_dir
!= INPUT_LAST_TEXT
)
704 g_free (in_start_dir
);
705 in_start_dir
= g_strdup (*start_dir
);
707 s
= tilde_expand (*start_dir
);
708 canonicalize_pathname (s
);
710 if (s
[0] == '.' && s
[1] == '\0')
712 *start_dir
= g_strdup (current_panel
->cwd
);
713 /* FIXME: is current_panel->cwd canonicalized? */
714 /* relative paths will be used in panelization */
715 *start_dir_len
= (ssize_t
) strlen (current_panel
->cwd
);
718 else if (g_path_is_absolute (s
))
725 /* relative paths will be used in panelization */
726 *start_dir
= mc_build_filename (current_panel
->cwd
, s
, (char *) NULL
);
727 *start_dir_len
= (ssize_t
) strlen (current_panel
->cwd
);
731 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
732 || (in_ignore
->buffer
[0] == '.' && in_ignore
->buffer
[1] == '\0'))
735 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
737 find_save_options ();
743 destroy_dlg (find_dlg
);
748 /* --------------------------------------------------------------------------------------------- */
750 #if GLIB_CHECK_VERSION (2, 14, 0)
752 push_directory (const char *dir
)
754 g_queue_push_head (&dir_queue
, (void *) dir
);
757 /* --------------------------------------------------------------------------------------------- */
762 return (char *) g_queue_pop_tail (&dir_queue
);
765 /* --------------------------------------------------------------------------------------------- */
766 /** Remove all the items from the stack */
771 g_queue_foreach (&dir_queue
, (GFunc
) g_free
, NULL
);
772 g_queue_clear (&dir_queue
);
775 /* --------------------------------------------------------------------------------------------- */
777 #else /* GLIB_CHECK_VERSION */
779 push_directory (const char *dir
)
783 new = g_new (dir_stack
, 1);
784 new->name
= (char *) dir
;
785 new->prev
= dir_stack_base
;
786 dir_stack_base
= new;
789 /* --------------------------------------------------------------------------------------------- */
796 if (dir_stack_base
!= NULL
)
799 name
= dir_stack_base
->name
;
800 next
= dir_stack_base
->prev
;
801 g_free (dir_stack_base
);
802 dir_stack_base
= next
;
808 /* --------------------------------------------------------------------------------------------- */
809 /** Remove all the items from the stack */
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 (&find_list
->widget
, WIDGET_DRAW
, 0);
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
)
970 gboolean ret_val
= FALSE
;
973 fname
= mc_build_filename (directory
, filename
, (char *) NULL
);
974 vpath
= vfs_path_from_str (fname
);
976 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
979 vfs_path_free (vpath
);
983 file_fd
= mc_open (fname
, O_RDONLY
);
985 vfs_path_free (vpath
);
990 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), str_trunc (filename
, FIND2_X_USE
));
992 status_update (buffer
);
995 tty_enable_interrupt_key ();
996 tty_got_interrupt ();
1002 gboolean has_newline
;
1004 gboolean found
= FALSE
;
1006 char result
[BUF_MEDIUM
];
1010 /* We've been previously suspended, start from the previous position */
1016 && (p
= get_line_at (file_fd
, buffer
, sizeof (buffer
),
1017 &pos
, &n_read
, &has_newline
)) != NULL
)
1019 if (!found
/* Search in binary line once */
1020 && mc_search_run (search_content_handle
,
1021 (const void *) p
, 0, strlen (p
), &found_len
))
1023 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1024 find_add_match (directory
, result
);
1029 if (found
&& options
.content_first_hit
)
1038 if ((line
& 0xff) == 0)
1040 FindProgressStatus res
;
1041 res
= check_find_events (h
);
1060 tty_disable_interrupt_key ();
1065 /* --------------------------------------------------------------------------------------------- */
1068 If dir is absolute, this means we're within dir and searching file here.
1069 If dir is relative, this means we're going to add dir to the directory stack.
1072 find_ignore_dir_search (const char *dir
)
1074 if (find_ignore_dirs
!= NULL
)
1076 const size_t dlen
= strlen (dir
);
1077 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1081 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1083 const size_t ilen
= strlen (*ignore_dir
);
1084 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1086 /* ignore dir is too long -- skip it */
1090 /* handle absolute and relative paths */
1091 switch (iabs
| dabs
)
1093 case 0: /* both paths are relative */
1094 case 3: /* both paths are abolute */
1095 /* if ignore dir is not a path of dir -- skip it */
1096 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1098 /* be sure that ignore dir is not a part of dir like:
1099 ignore dir is "h", dir is "home" */
1100 if (dir
[ilen
] == '\0' || dir
[ilen
] == PATH_SEP
)
1104 case 1: /* dir is absolute, ignore_dir is relative */
1108 d
= strstr (dir
, *ignore_dir
);
1109 if (d
!= NULL
&& d
[-1] == PATH_SEP
&& (d
[ilen
] == '\0' || d
[ilen
] == PATH_SEP
))
1113 case 2: /* dir is relative, ignore_dir is absolute */
1114 /* FIXME: skip this case */
1116 default: /* this cannot occurs */
1125 /* --------------------------------------------------------------------------------------------- */
1128 find_rotate_dash (const Dlg_head
* h
, gboolean finish
)
1130 static const char rotating_dash
[] = "|/-\\";
1131 static unsigned int pos
= 0;
1135 pos
= (pos
+ 1) % 4;
1136 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1137 dlg_move (h
, FIND2_Y
- 7, FIND2_X
- 4);
1138 tty_print_char (finish
? ' ' : rotating_dash
[pos
]);
1143 /* --------------------------------------------------------------------------------------------- */
1146 do_search (Dlg_head
* h
)
1148 static struct dirent
*dp
= NULL
;
1149 static DIR *dirp
= NULL
;
1150 static char *directory
= NULL
;
1151 struct stat tmp_stat
;
1152 static int subdirs_left
= 0;
1154 unsigned short count
;
1157 { /* someone forces me to close dirp */
1169 for (count
= 0; count
< 32; count
++)
1179 while (dirp
== NULL
)
1182 vfs_path_t
*tmp_vpath
;
1184 tty_setcolor (REVERSE_COLOR
);
1188 tmp
= pop_directory ();
1192 if (ignore_count
== 0)
1193 status_update (_("Finished"));
1196 char msg
[BUF_SMALL
];
1197 g_snprintf (msg
, sizeof (msg
),
1198 ngettext ("Finished (ignored %zd directory)",
1199 "Finished (ignored %zd directories)",
1200 ignore_count
), ignore_count
);
1201 status_update (msg
);
1203 find_rotate_dash (h
, TRUE
);
1208 /* handle absolute ignore dirs here */
1209 if (!find_ignore_dir_search (tmp
))
1218 tmp_vpath
= vfs_path_from_str (directory
);
1222 char buffer
[BUF_SMALL
];
1224 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"),
1225 str_trunc (directory
, FIND2_X_USE
));
1226 status_update (buffer
);
1228 /* mc_stat should not be called after mc_opendir
1229 because vfs_s_opendir modifies the st_nlink
1231 if (mc_stat (tmp_vpath
, &tmp_stat
) == 0)
1232 subdirs_left
= tmp_stat
.st_nlink
- 2;
1236 dirp
= mc_opendir (tmp_vpath
);
1237 vfs_path_free (tmp_vpath
);
1238 } /* while (!dirp) */
1240 /* skip invalid filenames */
1241 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1245 if (strcmp (dp
->d_name
, ".") == 0 || strcmp (dp
->d_name
, "..") == 0)
1247 /* skip invalid filenames */
1248 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1254 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1258 if ((subdirs_left
!= 0) && options
.find_recurs
&& (directory
!= NULL
))
1259 { /* Can directory be NULL ? */
1260 /* handle relative ignore dirs here */
1261 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1265 vfs_path_t
*tmp_vpath
;
1267 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1269 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1271 push_directory (vfs_path_to_str (tmp_vpath
));
1272 vfs_path_free (tmp_vpath
);
1276 vfs_path_free (tmp_vpath
);
1280 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1281 0, strlen (dp
->d_name
), &bytes_found
);
1285 if (content_pattern
== NULL
)
1286 find_add_match (directory
, dp
->d_name
);
1287 else if (search_content (h
, directory
, dp
->d_name
))
1292 /* skip invalid filenames */
1293 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1297 find_rotate_dash (h
, FALSE
);
1302 /* --------------------------------------------------------------------------------------------- */
1305 init_find_vars (void)
1312 /* Remove all the items from the stack */
1315 g_strfreev (find_ignore_dirs
);
1316 find_ignore_dirs
= NULL
;
1319 /* --------------------------------------------------------------------------------------------- */
1322 find_do_view_edit (int unparsed_view
, int edit
, char *dir
, char *file
)
1324 char *fullname
= NULL
;
1325 const char *filename
= NULL
;
1328 if (content_pattern
!= NULL
)
1330 filename
= strchr (file
+ 4, ':') + 1;
1331 line
= atoi (file
+ 4);
1335 filename
= file
+ 4;
1339 fullname
= mc_build_filename (dir
, filename
, (char *) NULL
);
1341 do_edit_at_line (fullname
, use_internal_edit
, line
);
1343 view_file_at_line (fullname
, unparsed_view
, use_internal_view
, line
);
1347 /* --------------------------------------------------------------------------------------------- */
1350 view_edit_currently_selected_file (int unparsed_view
, int edit
)
1355 listbox_get_current (find_list
, &text
, (void **) &dir
);
1357 if ((text
== NULL
) || (dir
== NULL
))
1358 return MSG_NOT_HANDLED
;
1360 find_do_view_edit (unparsed_view
, edit
, dir
, text
);
1364 /* --------------------------------------------------------------------------------------------- */
1367 find_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
1372 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1374 int unparsed_view
= (parm
== KEY_F (13));
1375 return view_edit_currently_selected_file (unparsed_view
, 0);
1377 if (parm
== KEY_F (4))
1379 return view_edit_currently_selected_file (0, 1);
1381 return MSG_NOT_HANDLED
;
1388 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1392 /* --------------------------------------------------------------------------------------------- */
1393 /** Handles the Stop/Start button in the find window */
1396 start_stop (WButton
* button
, int action
)
1402 set_idle_proc (find_dlg
, running
);
1403 is_start
= !is_start
;
1405 status_update (is_start
? _("Stopped") : _("Searching"));
1406 button_set_text (stop_button
, fbuts
[is_start
? 1 : 0].text
);
1411 /* --------------------------------------------------------------------------------------------- */
1412 /** Handle view command, when invoked as a button */
1415 find_do_view_file (WButton
* button
, int action
)
1420 view_edit_currently_selected_file (0, 0);
1424 /* --------------------------------------------------------------------------------------------- */
1425 /** Handle edit command, when invoked as a button */
1428 find_do_edit_file (WButton
* button
, int action
)
1433 view_edit_currently_selected_file (0, 1);
1437 /* --------------------------------------------------------------------------------------------- */
1443 static gboolean i18n_flag
= FALSE
;
1447 int i
= sizeof (fbuts
) / sizeof (fbuts
[0]);
1450 fbuts
[i
].text
= _(fbuts
[i
].text
);
1451 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1454 fbuts
[2].len
+= 2; /* DEFPUSH_BUTTON */
1457 #endif /* ENABLE_NLS */
1460 * Dynamically place buttons centered within current window size
1463 int l0
= max (fbuts
[0].len
, fbuts
[1].len
);
1464 int l1
= fbuts
[2].len
+ fbuts
[3].len
+ l0
+ fbuts
[4].len
;
1465 int l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
;
1468 /* Check, if both button rows fit within FIND2_X */
1469 FIND2_X
= max (l1
+ 9, COLS
- 16);
1470 FIND2_X
= max (l2
+ 8, FIND2_X
);
1472 /* compute amount of space between buttons for each row */
1473 r1
= (FIND2_X
- 4 - l1
) % 5;
1474 l1
= (FIND2_X
- 4 - l1
) / 5;
1475 r2
= (FIND2_X
- 4 - l2
) % 4;
1476 l2
= (FIND2_X
- 4 - l2
) / 4;
1478 /* ...and finally, place buttons */
1479 fbuts
[2].x
= 2 + r1
/ 2 + l1
;
1480 fbuts
[3].x
= fbuts
[2].x
+ fbuts
[2].len
+ l1
;
1481 fbuts
[0].x
= fbuts
[3].x
+ fbuts
[3].len
+ l1
;
1482 fbuts
[4].x
= fbuts
[0].x
+ l0
+ l1
;
1483 fbuts
[5].x
= 2 + r2
/ 2 + l2
;
1484 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ l2
;
1485 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ l2
;
1489 create_dlg (TRUE
, 0, 0, FIND2_Y
, FIND2_X
, dialog_colors
, find_callback
,
1490 "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
1492 add_widget (find_dlg
,
1493 button_new (FIND2_Y
- 3, fbuts
[7].x
, B_VIEW
, NORMAL_BUTTON
,
1494 fbuts
[7].text
, find_do_edit_file
));
1495 add_widget (find_dlg
,
1496 button_new (FIND2_Y
- 3, fbuts
[6].x
, B_VIEW
, NORMAL_BUTTON
,
1497 fbuts
[6].text
, find_do_view_file
));
1498 add_widget (find_dlg
,
1499 button_new (FIND2_Y
- 3, fbuts
[5].x
, B_PANELIZE
, NORMAL_BUTTON
, fbuts
[5].text
,
1502 add_widget (find_dlg
,
1503 button_new (FIND2_Y
- 4, fbuts
[4].x
, B_CANCEL
, NORMAL_BUTTON
, fbuts
[4].text
, NULL
));
1505 button_new (FIND2_Y
- 4, fbuts
[0].x
, B_STOP
, NORMAL_BUTTON
, fbuts
[0].text
, start_stop
);
1506 add_widget (find_dlg
, stop_button
);
1507 add_widget (find_dlg
,
1508 button_new (FIND2_Y
- 4, fbuts
[3].x
, B_AGAIN
, NORMAL_BUTTON
, fbuts
[3].text
, NULL
));
1509 add_widget (find_dlg
,
1510 button_new (FIND2_Y
- 4, fbuts
[2].x
, B_ENTER
, DEFPUSH_BUTTON
, fbuts
[2].text
, NULL
));
1512 status_label
= label_new (FIND2_Y
- 7, 4, _("Searching"));
1513 add_widget (find_dlg
, status_label
);
1515 found_num_label
= label_new (FIND2_Y
- 6, 4, "");
1516 add_widget (find_dlg
, found_num_label
);
1518 find_list
= listbox_new (2, 2, FIND2_Y
- 10, FIND2_X
- 4, FALSE
, NULL
);
1519 add_widget (find_dlg
, find_list
);
1522 /* --------------------------------------------------------------------------------------------- */
1529 search_content_handle
= mc_search_new (content_pattern
, -1);
1530 if (search_content_handle
)
1532 search_content_handle
->search_type
=
1533 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1534 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1535 search_content_handle
->whole_words
= options
.content_whole_words
;
1536 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1538 search_file_handle
= mc_search_new (find_pattern
, -1);
1539 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1540 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1541 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1542 search_file_handle
->is_entire_line
= options
.file_pattern
;
1546 set_idle_proc (find_dlg
, 1);
1547 ret
= run_dlg (find_dlg
);
1549 mc_search_free (search_file_handle
);
1550 search_file_handle
= NULL
;
1551 mc_search_free (search_content_handle
);
1552 search_content_handle
= NULL
;
1557 /* --------------------------------------------------------------------------------------------- */
1562 set_idle_proc (find_dlg
, 0);
1563 destroy_dlg (find_dlg
);
1566 /* --------------------------------------------------------------------------------------------- */
1569 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1570 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1572 int return_value
= 0;
1573 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1577 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1578 find_pattern
= (char *) pattern
;
1580 content_pattern
= NULL
;
1581 if (options
.content_use
&& content
!= NULL
&& str_is_valid_string (content
))
1582 content_pattern
= g_strdup (content
);
1585 parse_ignore_dirs (ignore_dirs
);
1586 push_directory (start_dir
);
1588 return_value
= run_process ();
1590 /* Clear variables */
1593 get_list_info (&file_tmp
, &dir_tmp
);
1596 *dirname
= g_strdup (dir_tmp
);
1598 *filename
= g_strdup (file_tmp
);
1600 if (return_value
== B_PANELIZE
&& *filename
)
1602 int status
, link_to_dir
, stale_link
;
1607 dir_list
*list
= ¤t_panel
->dir
;
1610 if (set_zero_dir (list
))
1613 for (i
= 0, entry
= find_list
->list
; entry
!= NULL
; i
++, entry
= g_list_next (entry
))
1615 const char *lc_filename
= NULL
;
1616 WLEntry
*le
= (WLEntry
*) entry
->data
;
1619 if ((le
->text
== NULL
) || (le
->data
== NULL
))
1622 if (content_pattern
!= NULL
)
1623 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1625 lc_filename
= le
->text
+ 4;
1627 name
= mc_build_filename (le
->data
, lc_filename
, (char *) NULL
);
1628 /* skip initial start dir */
1629 if (start_dir_len
< 0)
1633 p
= name
+ (size_t) start_dir_len
;
1638 status
= handle_path (list
, p
, &st
, next_free
, &link_to_dir
, &stale_link
);
1650 /* don't add files more than once to the panel */
1651 if (content_pattern
!= NULL
&& next_free
> 0
1652 && strcmp (list
->list
[next_free
- 1].fname
, p
) == 0)
1658 if (next_free
== 0) /* first turn i.e clean old list */
1659 panel_clean_dir (current_panel
);
1660 list
->list
[next_free
].fnamelen
= strlen (p
);
1661 list
->list
[next_free
].fname
= g_strndup (p
, list
->list
[next_free
].fnamelen
);
1662 list
->list
[next_free
].f
.marked
= 0;
1663 list
->list
[next_free
].f
.link_to_dir
= link_to_dir
;
1664 list
->list
[next_free
].f
.stale_link
= stale_link
;
1665 list
->list
[next_free
].f
.dir_size_computed
= 0;
1666 list
->list
[next_free
].st
= st
;
1667 list
->list
[next_free
].sort_key
= NULL
;
1668 list
->list
[next_free
].second_sort_key
= NULL
;
1671 if (!(next_free
& 15))
1677 current_panel
->count
= next_free
;
1678 current_panel
->is_panelized
= TRUE
;
1681 if (start_dir_len
< 0)
1685 strcpy (current_panel
->cwd
, PATH_SEP_STR
);
1686 ret
= chdir (PATH_SEP_STR
);
1688 panelize_save_panel (current_panel
);
1692 g_free (content_pattern
);
1694 do_search (NULL
); /* force do_search to release resources */
1698 return return_value
;
1701 /* --------------------------------------------------------------------------------------------- */
1702 /*** public functions ****************************************************************************/
1703 /* --------------------------------------------------------------------------------------------- */
1708 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1709 ssize_t start_dir_len
;
1710 char *filename
= NULL
, *dirname
= NULL
;
1713 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1715 if (pattern
[0] == '\0')
1716 break; /* nothing search */
1718 dirname
= filename
= NULL
;
1720 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
, &filename
);
1721 g_free (ignore_dirs
);
1726 if (dirname
!= NULL
)
1728 do_cd (dirname
, cd_exact
);
1729 if (filename
!= NULL
)
1730 try_to_select (current_panel
,
1731 filename
+ (content
!= NULL
1732 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1734 else if (filename
!= NULL
)
1735 do_cd (filename
, cd_exact
);
1749 if (v
== B_PANELIZE
)
1751 panel_re_sort (current_panel
);
1752 try_to_select (current_panel
, NULL
);
1758 /* --------------------------------------------------------------------------------------------- */