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 (content_label
), disable
);
409 widget_disable (WIDGET (in_with
), disable
);
410 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
411 widget_disable (WIDGET (content_regexp_cbox
), disable
);
412 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
414 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
416 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
421 if (sender
== WIDGET (ignore_dirs_cbox
))
423 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
425 widget_disable (WIDGET (in_ignore
), disable
);
430 return MSG_NOT_HANDLED
;
434 if (h
->ret_value
!= B_ENTER
)
437 /* check filename regexp */
438 if (!(file_pattern_cbox
->state
& C_BOOL
)
439 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->buffer
))
441 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
442 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
443 dlg_select_widget (in_name
);
447 /* check content regexp */
448 if ((content_use_cbox
->state
& C_BOOL
) && (content_regexp_cbox
->state
& C_BOOL
)
449 && (in_with
->buffer
[0] != '\0') && !find_check_regexp (in_with
->buffer
))
451 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
452 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
453 dlg_select_widget (in_with
);
460 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
464 /* --------------------------------------------------------------------------------------------- */
466 * find_parameters: gets information from the user
468 * If the return value is TRUE, then the following holds:
470 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
471 * They are newly allocated strings and must be freed when uneeded.
473 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
474 * of start_dir (which is absolute). It is used to get a relative pats of find results.
478 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
479 char **ignore_dirs
, char **pattern
, char **content
)
481 gboolean return_value
;
484 const char *file_case_label
= N_("Cas&e sensitive");
485 const char *file_pattern_label
= N_("&Using shell patterns");
486 const char *file_recurs_label
= N_("&Find recursively");
487 const char *file_skip_hidden_label
= N_("S&kip hidden");
489 const char *file_all_charsets_label
= N_("&All charsets");
493 const char *content_use_label
= N_("Sea&rch for content");
494 const char *content_case_label
= N_("Case sens&itive");
495 const char *content_regexp_label
= N_("Re&gular expression");
496 const char *content_first_hit_label
= N_("Fir&st hit");
497 const char *content_whole_words_label
= N_("&Whole words");
499 const char *content_all_charsets_label
= N_("A&ll charsets");
502 const char *buts
[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
511 int i
= sizeof (buts
) / sizeof (buts
[0]);
513 buts
[i
] = _(buts
[i
]);
515 file_case_label
= _(file_case_label
);
516 file_pattern_label
= _(file_pattern_label
);
517 file_recurs_label
= _(file_recurs_label
);
518 file_skip_hidden_label
= _(file_skip_hidden_label
);
520 file_all_charsets_label
= _(file_all_charsets_label
);
521 content_all_charsets_label
= _(content_all_charsets_label
);
523 content_use_label
= _(content_use_label
);
524 content_case_label
= _(content_case_label
);
525 content_regexp_label
= _(content_regexp_label
);
526 content_first_hit_label
= _(content_first_hit_label
);
527 content_whole_words_label
= _(content_whole_words_label
);
529 #endif /* ENABLE_NLS */
531 b0
= str_term_width1 (buts
[0]) + 6; /* default button */
532 b1
= str_term_width1 (buts
[1]) + 4;
533 b2
= str_term_width1 (buts
[2]) + 4;
535 find_load_options ();
537 if (in_start_dir
== NULL
)
538 in_start_dir
= g_strdup (".");
540 disable
= !options
.content_use
;
543 create_dlg (TRUE
, 0, 0, FIND_Y
, FIND_X
, dialog_colors
,
544 find_parm_callback
, NULL
, "[Find File]", _("Find File"),
545 DLG_CENTER
| DLG_REVERSE
);
547 add_widget (find_dlg
,
548 button_new (FIND_Y
- 3, FIND_X
* 3 / 4 - b1
/ 2, B_CANCEL
, NORMAL_BUTTON
, buts
[1],
550 add_widget (find_dlg
,
551 button_new (FIND_Y
- 3, FIND_X
/ 4 - b0
/ 2, B_ENTER
, DEFPUSH_BUTTON
, buts
[0], 0));
553 cbox_position
= FIND_Y
- 5;
555 content_first_hit_cbox
=
556 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_first_hit
,
557 content_first_hit_label
);
558 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
559 add_widget (find_dlg
, content_first_hit_cbox
);
561 content_whole_words_cbox
=
562 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_whole_words
,
563 content_whole_words_label
);
564 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
565 add_widget (find_dlg
, content_whole_words_cbox
);
568 content_all_charsets_cbox
= check_new (cbox_position
--, FIND_X
/ 2 + 1,
569 options
.content_all_charsets
,
570 content_all_charsets_label
);
571 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
572 add_widget (find_dlg
, content_all_charsets_cbox
);
575 content_case_sens_cbox
=
576 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_case_sens
, content_case_label
);
577 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
578 add_widget (find_dlg
, content_case_sens_cbox
);
580 content_regexp_cbox
=
581 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_regexp
, content_regexp_label
);
582 widget_disable (WIDGET (content_regexp_cbox
), disable
);
583 add_widget (find_dlg
, content_regexp_cbox
);
585 cbox_position
= FIND_Y
- 6;
587 skip_hidden_cbox
= check_new (cbox_position
--, 3, options
.skip_hidden
, file_skip_hidden_label
);
588 add_widget (find_dlg
, skip_hidden_cbox
);
591 file_all_charsets_cbox
=
592 check_new (cbox_position
--, 3, options
.file_all_charsets
, file_all_charsets_label
);
593 add_widget (find_dlg
, file_all_charsets_cbox
);
596 file_case_sens_cbox
= check_new (cbox_position
--, 3, options
.file_case_sens
, file_case_label
);
597 add_widget (find_dlg
, file_case_sens_cbox
);
599 file_pattern_cbox
= check_new (cbox_position
--, 3, options
.file_pattern
, file_pattern_label
);
600 add_widget (find_dlg
, file_pattern_cbox
);
602 recursively_cbox
= check_new (cbox_position
, 3, options
.find_recurs
, file_recurs_label
);
603 add_widget (find_dlg
, recursively_cbox
);
605 /* This checkbox is located in the second column */
607 check_new (cbox_position
, FIND_X
/ 2 + 1, options
.content_use
, content_use_label
);
608 add_widget (find_dlg
, content_use_cbox
);
611 input_new (8, FIND_X
/ 2 + 1, input_get_default_colors (), FIND_X
/ 2 - 4, INPUT_LAST_TEXT
,
612 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_DEFAULT
);
613 widget_disable (WIDGET (in_with
), disable
);
614 add_widget (find_dlg
, in_with
);
616 content_label
= label_new (7, FIND_X
/ 2 + 1, _("Content:"));
617 widget_disable (WIDGET (content_label
), disable
);
618 add_widget (find_dlg
, content_label
);
620 in_name
= input_new (8, 3, input_get_default_colors (),
621 FIND_X
/ 2 - 4, INPUT_LAST_TEXT
, "name", INPUT_COMPLETE_DEFAULT
);
622 add_widget (find_dlg
, in_name
);
623 add_widget (find_dlg
, label_new (7, 3, _("File name:")));
625 in_ignore
= input_new (5, 3, input_get_default_colors (), FIND_X
- 6,
626 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "",
627 "ignoredirs", INPUT_COMPLETE_DEFAULT
);
628 widget_disable (WIDGET (in_ignore
), !options
.ignore_dirs_enable
);
629 add_widget (find_dlg
, in_ignore
);
632 check_new (4, 3, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
633 add_widget (find_dlg
, ignore_dirs_cbox
);
635 add_widget (find_dlg
, button_new (3, FIND_X
- b2
- 2, B_TREE
, NORMAL_BUTTON
, buts
[2], 0));
637 in_start
= input_new (3, 3, input_get_default_colors (),
638 FIND_X
- b2
- 6, in_start_dir
, "start", INPUT_COMPLETE_DEFAULT
);
639 add_widget (find_dlg
, in_start
);
640 add_widget (find_dlg
, label_new (2, 3, _("Start at:")));
643 dlg_select_widget (in_name
);
645 switch (run_dlg (find_dlg
))
648 return_value
= FALSE
;
655 temp_dir
= in_start
->buffer
;
656 if ((temp_dir
[0] == '\0') || ((temp_dir
[0] == '.') && (temp_dir
[1] == '\0')))
657 temp_dir
= vfs_path_to_str (current_panel
->cwd_vpath
);
659 temp_dir
= g_strdup (temp_dir
);
661 if (in_start_dir
!= INPUT_LAST_TEXT
)
662 g_free (in_start_dir
);
663 in_start_dir
= tree_box (temp_dir
);
664 if (in_start_dir
== NULL
)
665 in_start_dir
= temp_dir
;
669 input_assign_text (in_start
, in_start_dir
);
671 /* Warning: Dreadful goto */
680 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
681 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
683 options
.content_use
= content_use_cbox
->state
& C_BOOL
;
684 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
685 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
686 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
687 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
688 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
689 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
690 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
691 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
692 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
693 g_free (options
.ignore_dirs
);
694 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
696 *content
= (options
.content_use
&& in_with
->buffer
[0] != '\0')
697 ? g_strdup (in_with
->buffer
) : NULL
;
698 *start_dir
= in_start
->buffer
[0] != '\0' ? in_start
->buffer
: (char *) ".";
699 *pattern
= g_strdup (in_name
->buffer
);
700 if (in_start_dir
!= INPUT_LAST_TEXT
)
701 g_free (in_start_dir
);
702 in_start_dir
= g_strdup (*start_dir
);
704 s
= tilde_expand (*start_dir
);
705 canonicalize_pathname (s
);
707 if (s
[0] == '.' && s
[1] == '\0')
709 *start_dir
= vfs_path_to_str (current_panel
->cwd_vpath
);
710 /* FIXME: is current_panel->cwd_vpath canonicalized? */
711 /* relative paths will be used in panelization */
712 *start_dir_len
= (ssize_t
) strlen (*start_dir
);
715 else if (g_path_is_absolute (s
))
722 /* relative paths will be used in panelization */
725 cwd_str
= vfs_path_to_str (current_panel
->cwd_vpath
);
726 *start_dir
= mc_build_filename (cwd_str
, s
, (char *) NULL
);
727 *start_dir_len
= (ssize_t
) strlen (cwd_str
);
732 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
733 || (in_ignore
->buffer
[0] == '.' && in_ignore
->buffer
[1] == '\0'))
736 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
738 find_save_options ();
744 destroy_dlg (find_dlg
);
749 /* --------------------------------------------------------------------------------------------- */
751 #if GLIB_CHECK_VERSION (2, 14, 0)
753 push_directory (const vfs_path_t
* dir
)
755 g_queue_push_head (&dir_queue
, (void *) dir
);
758 /* --------------------------------------------------------------------------------------------- */
760 static inline vfs_path_t
*
763 return (vfs_path_t
*) g_queue_pop_tail (&dir_queue
);
766 /* --------------------------------------------------------------------------------------------- */
767 /** Remove all the items from the stack */
772 g_queue_foreach (&dir_queue
, (GFunc
) vfs_path_free
, NULL
);
773 g_queue_clear (&dir_queue
);
776 /* --------------------------------------------------------------------------------------------- */
778 #else /* GLIB_CHECK_VERSION */
780 push_directory (const vfs_path_t
* dir
)
784 new = g_new (dir_stack
, 1);
785 new->name
= (vfs_path_t
*) dir
;
786 new->prev
= dir_stack_base
;
787 dir_stack_base
= new;
790 /* --------------------------------------------------------------------------------------------- */
795 vfs_path_t
*name
= NULL
;
797 if (dir_stack_base
!= NULL
)
800 name
= dir_stack_base
->name
;
801 next
= dir_stack_base
->prev
;
802 g_free (dir_stack_base
);
803 dir_stack_base
= next
;
809 /* --------------------------------------------------------------------------------------------- */
810 /** Remove all the items from the stack */
815 vfs_path_t
*dir
= NULL
;
817 while ((dir
= pop_directory ()) != NULL
)
820 #endif /* GLIB_CHECK_VERSION */
822 /* --------------------------------------------------------------------------------------------- */
825 insert_file (const char *dir
, const char *file
)
827 char *tmp_name
= NULL
;
828 static char *dirname
= NULL
;
830 while (dir
[0] == PATH_SEP
&& dir
[1] == PATH_SEP
)
835 if (strcmp (old_dir
, dir
))
838 old_dir
= g_strdup (dir
);
839 dirname
= add_to_list (dir
, NULL
);
844 old_dir
= g_strdup (dir
);
845 dirname
= add_to_list (dir
, NULL
);
848 tmp_name
= g_strdup_printf (" %s", file
);
849 add_to_list (tmp_name
, dirname
);
853 /* --------------------------------------------------------------------------------------------- */
856 find_add_match (const char *dir
, const char *file
)
858 insert_file (dir
, file
);
862 listbox_select_first (find_list
);
863 send_message (WIDGET (find_list
), NULL
, WIDGET_DRAW
, 0, NULL
);
869 /* --------------------------------------------------------------------------------------------- */
873 * Returns malloced null-terminated line from file file_fd.
874 * Input is buffered in buf_size long buffer.
875 * Current pos in buf is stored in pos.
876 * n_read - number of read chars.
877 * has_newline - is there newline ?
881 get_line_at (int file_fd
, char *buf
, int buf_size
, int *pos
, int *n_read
, gboolean
* has_newline
)
893 *n_read
= mc_read (file_fd
, buf
, buf_size
);
901 /* skip possible leading zero(s) */
907 if (i
>= buffer_size
- 1)
908 buffer
= g_realloc (buffer
, buffer_size
+= 80);
917 *has_newline
= (ch
!= '\0');
925 /* --------------------------------------------------------------------------------------------- */
927 static FindProgressStatus
928 check_find_events (Dlg_head
* h
)
934 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
937 dlg_process_event (h
, c
, &event
);
938 if (h
->ret_value
== B_ENTER
939 || h
->ret_value
== B_CANCEL
|| h
->ret_value
== B_AGAIN
|| h
->ret_value
== B_PANELIZE
)
941 /* dialog terminated */
944 if (!(h
->flags
& DLG_WANT_IDLE
))
946 /* searching suspended */
954 /* --------------------------------------------------------------------------------------------- */
958 * Search the content_pattern string in the DIRECTORY/FILE.
959 * It will add the found entries to the find listbox.
961 * returns FALSE if do_search should look for another file
962 * TRUE if do_search should exit and proceed to the event handler
966 search_content (Dlg_head
* h
, const char *directory
, const char *filename
)
971 gboolean ret_val
= FALSE
;
974 vpath
= vfs_path_build_filename (directory
, filename
, (char *) NULL
);
976 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
978 vfs_path_free (vpath
);
982 file_fd
= mc_open (vpath
, O_RDONLY
);
983 vfs_path_free (vpath
);
988 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), str_trunc (filename
, FIND2_X_USE
));
990 status_update (buffer
);
993 tty_enable_interrupt_key ();
994 tty_got_interrupt ();
1000 gboolean has_newline
;
1002 gboolean found
= FALSE
;
1004 char result
[BUF_MEDIUM
];
1008 /* We've been previously suspended, start from the previous position */
1014 && (p
= get_line_at (file_fd
, buffer
, sizeof (buffer
),
1015 &pos
, &n_read
, &has_newline
)) != NULL
)
1017 if (!found
/* Search in binary line once */
1018 && mc_search_run (search_content_handle
,
1019 (const void *) p
, 0, strlen (p
), &found_len
))
1021 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1022 find_add_match (directory
, result
);
1027 if (found
&& options
.content_first_hit
)
1036 if ((line
& 0xff) == 0)
1038 FindProgressStatus res
;
1039 res
= check_find_events (h
);
1058 tty_disable_interrupt_key ();
1063 /* --------------------------------------------------------------------------------------------- */
1066 If dir is absolute, this means we're within dir and searching file here.
1067 If dir is relative, this means we're going to add dir to the directory stack.
1070 find_ignore_dir_search (const char *dir
)
1072 if (find_ignore_dirs
!= NULL
)
1074 const size_t dlen
= strlen (dir
);
1075 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1079 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1081 const size_t ilen
= strlen (*ignore_dir
);
1082 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1084 /* ignore dir is too long -- skip it */
1088 /* handle absolute and relative paths */
1089 switch (iabs
| dabs
)
1091 case 0: /* both paths are relative */
1092 case 3: /* both paths are abolute */
1093 /* if ignore dir is not a path of dir -- skip it */
1094 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1096 /* be sure that ignore dir is not a part of dir like:
1097 ignore dir is "h", dir is "home" */
1098 if (dir
[ilen
] == '\0' || dir
[ilen
] == PATH_SEP
)
1102 case 1: /* dir is absolute, ignore_dir is relative */
1106 d
= strstr (dir
, *ignore_dir
);
1107 if (d
!= NULL
&& d
[-1] == PATH_SEP
&& (d
[ilen
] == '\0' || d
[ilen
] == PATH_SEP
))
1111 case 2: /* dir is relative, ignore_dir is absolute */
1112 /* FIXME: skip this case */
1114 default: /* this cannot occurs */
1123 /* --------------------------------------------------------------------------------------------- */
1126 find_rotate_dash (const Dlg_head
* h
, gboolean finish
)
1128 static const char rotating_dash
[] = "|/-\\";
1129 static unsigned int pos
= 0;
1133 pos
= (pos
+ 1) % 4;
1134 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1135 widget_move (h
, FIND2_Y
- 7, FIND2_X
- 4);
1136 tty_print_char (finish
? ' ' : rotating_dash
[pos
]);
1141 /* --------------------------------------------------------------------------------------------- */
1144 do_search (Dlg_head
* h
)
1146 static struct dirent
*dp
= NULL
;
1147 static DIR *dirp
= NULL
;
1148 static char *directory
= NULL
;
1149 struct stat tmp_stat
;
1150 static int subdirs_left
= 0;
1152 unsigned short count
;
1155 { /* someone forces me to close dirp */
1167 for (count
= 0; count
< 32; count
++)
1177 while (dirp
== NULL
)
1179 vfs_path_t
*tmp_vpath
= NULL
;
1181 tty_setcolor (REVERSE_COLOR
);
1185 tmp_vpath
= pop_directory ();
1186 if (tmp_vpath
== NULL
)
1189 if (ignore_count
== 0)
1190 status_update (_("Finished"));
1193 char msg
[BUF_SMALL
];
1194 g_snprintf (msg
, sizeof (msg
),
1195 ngettext ("Finished (ignored %zd directory)",
1196 "Finished (ignored %zd directories)",
1197 ignore_count
), ignore_count
);
1198 status_update (msg
);
1200 find_rotate_dash (h
, TRUE
);
1205 /* handle absolute ignore dirs here */
1210 tmp
= vfs_path_to_str (tmp_vpath
);
1211 ok
= find_ignore_dir_search (tmp
);
1217 vfs_path_free (tmp_vpath
);
1222 directory
= vfs_path_to_str (tmp_vpath
);
1226 char buffer
[BUF_SMALL
];
1228 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"),
1229 str_trunc (directory
, FIND2_X_USE
));
1230 status_update (buffer
);
1232 /* mc_stat should not be called after mc_opendir
1233 because vfs_s_opendir modifies the st_nlink
1235 if (mc_stat (tmp_vpath
, &tmp_stat
) == 0)
1236 subdirs_left
= tmp_stat
.st_nlink
- 2;
1240 dirp
= mc_opendir (tmp_vpath
);
1241 vfs_path_free (tmp_vpath
);
1242 } /* while (!dirp) */
1244 /* skip invalid filenames */
1245 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1249 if (strcmp (dp
->d_name
, ".") == 0 || strcmp (dp
->d_name
, "..") == 0)
1251 /* skip invalid filenames */
1252 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1258 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1262 if ((subdirs_left
!= 0) && options
.find_recurs
&& (directory
!= NULL
))
1263 { /* Can directory be NULL ? */
1264 /* handle relative ignore dirs here */
1265 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1269 vfs_path_t
*tmp_vpath
;
1271 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1273 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1275 push_directory (tmp_vpath
);
1279 vfs_path_free (tmp_vpath
);
1283 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1284 0, strlen (dp
->d_name
), &bytes_found
);
1288 if (content_pattern
== NULL
)
1289 find_add_match (directory
, dp
->d_name
);
1290 else if (search_content (h
, directory
, dp
->d_name
))
1295 /* skip invalid filenames */
1296 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1300 find_rotate_dash (h
, FALSE
);
1305 /* --------------------------------------------------------------------------------------------- */
1308 init_find_vars (void)
1315 /* Remove all the items from the stack */
1318 g_strfreev (find_ignore_dirs
);
1319 find_ignore_dirs
= NULL
;
1322 /* --------------------------------------------------------------------------------------------- */
1325 find_do_view_edit (int unparsed_view
, int edit
, char *dir
, char *file
)
1327 char *fullname
= NULL
;
1328 const char *filename
= NULL
;
1330 vfs_path_t
*fullname_vpath
;
1332 if (content_pattern
!= NULL
)
1334 filename
= strchr (file
+ 4, ':') + 1;
1335 line
= atoi (file
+ 4);
1339 filename
= file
+ 4;
1343 fullname_vpath
= vfs_path_build_filename (dir
, filename
, (char *) NULL
);
1345 do_edit_at_line (fullname_vpath
, use_internal_edit
, line
);
1347 view_file_at_line (fullname_vpath
, unparsed_view
, use_internal_view
, line
);
1348 vfs_path_free (fullname_vpath
);
1352 /* --------------------------------------------------------------------------------------------- */
1355 view_edit_currently_selected_file (int unparsed_view
, int edit
)
1360 listbox_get_current (find_list
, &text
, (void **) &dir
);
1362 if ((text
== NULL
) || (dir
== NULL
))
1363 return MSG_NOT_HANDLED
;
1365 find_do_view_edit (unparsed_view
, edit
, dir
, text
);
1369 /* --------------------------------------------------------------------------------------------- */
1372 find_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
1377 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1379 int unparsed_view
= (parm
== KEY_F (13));
1380 return view_edit_currently_selected_file (unparsed_view
, 0);
1382 if (parm
== KEY_F (4))
1384 return view_edit_currently_selected_file (0, 1);
1386 return MSG_NOT_HANDLED
;
1393 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1397 /* --------------------------------------------------------------------------------------------- */
1398 /** Handles the Stop/Start button in the find window */
1401 start_stop (WButton
* button
, int action
)
1407 set_idle_proc (find_dlg
, running
);
1408 is_start
= !is_start
;
1410 status_update (is_start
? _("Stopped") : _("Searching"));
1411 button_set_text (stop_button
, fbuts
[is_start
? 1 : 0].text
);
1416 /* --------------------------------------------------------------------------------------------- */
1417 /** Handle view command, when invoked as a button */
1420 find_do_view_file (WButton
* button
, int action
)
1425 view_edit_currently_selected_file (0, 0);
1429 /* --------------------------------------------------------------------------------------------- */
1430 /** Handle edit command, when invoked as a button */
1433 find_do_edit_file (WButton
* button
, int action
)
1438 view_edit_currently_selected_file (0, 1);
1442 /* --------------------------------------------------------------------------------------------- */
1448 static gboolean i18n_flag
= FALSE
;
1452 int i
= sizeof (fbuts
) / sizeof (fbuts
[0]);
1455 fbuts
[i
].text
= _(fbuts
[i
].text
);
1456 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1459 fbuts
[2].len
+= 2; /* DEFPUSH_BUTTON */
1462 #endif /* ENABLE_NLS */
1465 * Dynamically place buttons centered within current window size
1468 int l0
= max (fbuts
[0].len
, fbuts
[1].len
);
1469 int l1
= fbuts
[2].len
+ fbuts
[3].len
+ l0
+ fbuts
[4].len
;
1470 int l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
;
1473 /* Check, if both button rows fit within FIND2_X */
1474 FIND2_X
= max (l1
+ 9, COLS
- 16);
1475 FIND2_X
= max (l2
+ 8, FIND2_X
);
1477 /* compute amount of space between buttons for each row */
1478 r1
= (FIND2_X
- 4 - l1
) % 5;
1479 l1
= (FIND2_X
- 4 - l1
) / 5;
1480 r2
= (FIND2_X
- 4 - l2
) % 4;
1481 l2
= (FIND2_X
- 4 - l2
) / 4;
1483 /* ...and finally, place buttons */
1484 fbuts
[2].x
= 2 + r1
/ 2 + l1
;
1485 fbuts
[3].x
= fbuts
[2].x
+ fbuts
[2].len
+ l1
;
1486 fbuts
[0].x
= fbuts
[3].x
+ fbuts
[3].len
+ l1
;
1487 fbuts
[4].x
= fbuts
[0].x
+ l0
+ l1
;
1488 fbuts
[5].x
= 2 + r2
/ 2 + l2
;
1489 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ l2
;
1490 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ l2
;
1494 create_dlg (TRUE
, 0, 0, FIND2_Y
, FIND2_X
, dialog_colors
, find_callback
, NULL
,
1495 "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
1497 add_widget (find_dlg
,
1498 button_new (FIND2_Y
- 3, fbuts
[7].x
, B_VIEW
, NORMAL_BUTTON
,
1499 fbuts
[7].text
, find_do_edit_file
));
1500 add_widget (find_dlg
,
1501 button_new (FIND2_Y
- 3, fbuts
[6].x
, B_VIEW
, NORMAL_BUTTON
,
1502 fbuts
[6].text
, find_do_view_file
));
1503 add_widget (find_dlg
,
1504 button_new (FIND2_Y
- 3, fbuts
[5].x
, B_PANELIZE
, NORMAL_BUTTON
, fbuts
[5].text
,
1507 add_widget (find_dlg
,
1508 button_new (FIND2_Y
- 4, fbuts
[4].x
, B_CANCEL
, NORMAL_BUTTON
, fbuts
[4].text
, NULL
));
1510 button_new (FIND2_Y
- 4, fbuts
[0].x
, B_STOP
, NORMAL_BUTTON
, fbuts
[0].text
, start_stop
);
1511 add_widget (find_dlg
, stop_button
);
1512 add_widget (find_dlg
,
1513 button_new (FIND2_Y
- 4, fbuts
[3].x
, B_AGAIN
, NORMAL_BUTTON
, fbuts
[3].text
, NULL
));
1514 add_widget (find_dlg
,
1515 button_new (FIND2_Y
- 4, fbuts
[2].x
, B_ENTER
, DEFPUSH_BUTTON
, fbuts
[2].text
, NULL
));
1517 status_label
= label_new (FIND2_Y
- 7, 4, _("Searching"));
1518 add_widget (find_dlg
, status_label
);
1520 found_num_label
= label_new (FIND2_Y
- 6, 4, "");
1521 add_widget (find_dlg
, found_num_label
);
1523 find_list
= listbox_new (2, 2, FIND2_Y
- 10, FIND2_X
- 4, FALSE
, NULL
);
1524 add_widget (find_dlg
, find_list
);
1527 /* --------------------------------------------------------------------------------------------- */
1534 search_content_handle
= mc_search_new (content_pattern
, -1);
1535 if (search_content_handle
)
1537 search_content_handle
->search_type
=
1538 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1539 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1540 search_content_handle
->whole_words
= options
.content_whole_words
;
1541 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1543 search_file_handle
= mc_search_new (find_pattern
, -1);
1544 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1545 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1546 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1547 search_file_handle
->is_entire_line
= options
.file_pattern
;
1551 set_idle_proc (find_dlg
, 1);
1552 ret
= run_dlg (find_dlg
);
1554 mc_search_free (search_file_handle
);
1555 search_file_handle
= NULL
;
1556 mc_search_free (search_content_handle
);
1557 search_content_handle
= NULL
;
1562 /* --------------------------------------------------------------------------------------------- */
1567 set_idle_proc (find_dlg
, 0);
1568 destroy_dlg (find_dlg
);
1571 /* --------------------------------------------------------------------------------------------- */
1574 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1575 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1577 int return_value
= 0;
1578 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1582 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1583 find_pattern
= (char *) pattern
;
1585 content_pattern
= NULL
;
1586 if (options
.content_use
&& content
!= NULL
&& str_is_valid_string (content
))
1587 content_pattern
= g_strdup (content
);
1590 parse_ignore_dirs (ignore_dirs
);
1591 push_directory (vfs_path_from_str (start_dir
));
1593 return_value
= run_process ();
1595 /* Clear variables */
1598 get_list_info (&file_tmp
, &dir_tmp
);
1601 *dirname
= g_strdup (dir_tmp
);
1603 *filename
= g_strdup (file_tmp
);
1605 if (return_value
== B_PANELIZE
&& *filename
)
1607 int status
, link_to_dir
, stale_link
;
1612 dir_list
*list
= ¤t_panel
->dir
;
1615 if (set_zero_dir (list
))
1618 for (i
= 0, entry
= find_list
->list
; entry
!= NULL
; i
++, entry
= g_list_next (entry
))
1620 const char *lc_filename
= NULL
;
1621 WLEntry
*le
= (WLEntry
*) entry
->data
;
1624 if ((le
->text
== NULL
) || (le
->data
== NULL
))
1627 if (content_pattern
!= NULL
)
1628 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1630 lc_filename
= le
->text
+ 4;
1632 name
= mc_build_filename (le
->data
, lc_filename
, (char *) NULL
);
1633 /* skip initial start dir */
1634 if (start_dir_len
< 0)
1638 p
= name
+ (size_t) start_dir_len
;
1643 status
= handle_path (list
, p
, &st
, next_free
, &link_to_dir
, &stale_link
);
1655 /* don't add files more than once to the panel */
1656 if (content_pattern
!= NULL
&& next_free
> 0
1657 && strcmp (list
->list
[next_free
- 1].fname
, p
) == 0)
1663 if (next_free
== 0) /* first turn i.e clean old list */
1664 panel_clean_dir (current_panel
);
1665 list
->list
[next_free
].fnamelen
= strlen (p
);
1666 list
->list
[next_free
].fname
= g_strndup (p
, list
->list
[next_free
].fnamelen
);
1667 list
->list
[next_free
].f
.marked
= 0;
1668 list
->list
[next_free
].f
.link_to_dir
= link_to_dir
;
1669 list
->list
[next_free
].f
.stale_link
= stale_link
;
1670 list
->list
[next_free
].f
.dir_size_computed
= 0;
1671 list
->list
[next_free
].st
= st
;
1672 list
->list
[next_free
].sort_key
= NULL
;
1673 list
->list
[next_free
].second_sort_key
= NULL
;
1676 if (!(next_free
& 15))
1682 current_panel
->count
= next_free
;
1683 current_panel
->is_panelized
= TRUE
;
1686 if (start_dir_len
< 0)
1689 vfs_path_free (current_panel
->cwd_vpath
);
1690 current_panel
->cwd_vpath
= vfs_path_from_str (PATH_SEP_STR
);
1691 ret
= chdir (PATH_SEP_STR
);
1693 panelize_save_panel (current_panel
);
1697 g_free (content_pattern
);
1699 do_search (NULL
); /* force do_search to release resources */
1703 return return_value
;
1706 /* --------------------------------------------------------------------------------------------- */
1707 /*** public functions ****************************************************************************/
1708 /* --------------------------------------------------------------------------------------------- */
1713 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1714 ssize_t start_dir_len
;
1715 char *filename
= NULL
, *dirname
= NULL
;
1718 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1720 if (pattern
[0] == '\0')
1721 break; /* nothing search */
1723 dirname
= filename
= NULL
;
1725 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
, &filename
);
1726 g_free (ignore_dirs
);
1731 if (dirname
!= NULL
)
1733 vfs_path_t
*dirname_vpath
;
1735 dirname_vpath
= vfs_path_from_str (dirname
);
1736 do_cd (dirname_vpath
, cd_exact
);
1737 vfs_path_free (dirname_vpath
);
1738 if (filename
!= NULL
)
1739 try_to_select (current_panel
,
1740 filename
+ (content
!= NULL
1741 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1743 else if (filename
!= NULL
)
1745 vfs_path_t
*filename_vpath
;
1747 filename_vpath
= vfs_path_from_str (filename
);
1748 do_cd (filename_vpath
, cd_exact
);
1749 vfs_path_free (filename_vpath
);
1764 if (v
== B_PANELIZE
)
1766 panel_re_sort (current_panel
);
1767 try_to_select (current_panel
, NULL
);
1773 /* --------------------------------------------------------------------------------------------- */