2 Find file command for the Midnight Commander
4 Copyright (C) 1995-2016
5 Free Software Foundation, Inc.
9 Slava Zanko <slavazanko@gmail.com>, 2013
10 Andrew Borodin <aborodin@vmail.ru>, 2013
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 * \brief Source: Find file command
41 #include "lib/global.h"
43 #include "lib/tty/tty.h"
44 #include "lib/tty/key.h"
46 #include "lib/search.h"
47 #include "lib/mcconfig.h"
48 #include "lib/vfs/vfs.h"
49 #include "lib/strutil.h"
50 #include "lib/widget.h"
51 #include "lib/util.h" /* canonicalize_pathname() */
53 #include "src/setup.h" /* verbose */
54 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
57 #include "cmd.h" /* view_file_at_line() */
58 #include "midnight.h" /* current_panel */
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 #define MAX_REFRESH_INTERVAL (G_USEC_PER_SEC / 20) /* 50 ms */
69 #define MIN_REFRESH_FILE_SIZE (256 * 1024) /* 256 KB */
71 /*** file scope type declarations ****************************************************************/
73 /* A couple of extra messages we need */
90 /* find file options */
93 /* file name options */
94 gboolean file_case_sens
;
95 gboolean file_pattern
;
98 gboolean file_all_charsets
;
100 /* file content options */
101 gboolean content_case_sens
;
102 gboolean content_regexp
;
103 gboolean content_first_hit
;
104 gboolean content_whole_words
;
105 gboolean content_all_charsets
;
107 /* whether use ignore dirs or not */
108 gboolean ignore_dirs_enable
;
109 /* list of directories to be ignored, separated by ':' */
111 } find_file_options_t
;
118 } find_match_location_t
;
120 /*** file scope variables ************************************************************************/
122 /* button callbacks */
123 static int start_stop (WButton
* button
, int action
);
124 static int find_do_view_file (WButton
* button
, int action
);
125 static int find_do_edit_file (WButton
* button
, int action
);
127 /* Parsed ignore dirs */
128 static char **find_ignore_dirs
= NULL
;
130 /* static variables to remember find parameters */
131 static WInput
*in_start
; /* Start path */
132 static WInput
*in_name
; /* Filename */
133 static WInput
*in_with
; /* Text */
134 static WInput
*in_ignore
;
135 static WLabel
*content_label
; /* 'Content:' label */
136 static WCheck
*file_case_sens_cbox
; /* "case sensitive" checkbox */
137 static WCheck
*file_pattern_cbox
; /* File name is glob or regexp */
138 static WCheck
*recursively_cbox
;
139 static WCheck
*skip_hidden_cbox
;
140 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
141 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
142 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
143 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
145 static WCheck
*file_all_charsets_cbox
;
146 static WCheck
*content_all_charsets_cbox
;
148 static WCheck
*ignore_dirs_cbox
;
150 static gboolean running
= FALSE
; /* nice flag */
151 static char *find_pattern
= NULL
; /* Pattern to search */
152 static char *content_pattern
= NULL
; /* pattern to search inside files; if
153 content_regexp_flag is true, it contains the
154 regex pattern, else the search string. */
155 static unsigned long matches
; /* Number of matches */
156 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
157 static char *old_dir
= NULL
;
159 static struct timeval last_refresh
;
161 /* Where did we stop */
162 static gboolean resuming
;
163 static int last_line
;
165 static off_t last_off
;
168 static size_t ignore_count
= 0;
170 static WDialog
*find_dlg
; /* The dialog */
171 static WLabel
*status_label
; /* Finished, Searching etc. */
172 static WLabel
*found_num_label
; /* Number of found items */
174 /* This keeps track of the directory stack */
175 static GQueue dir_queue
= G_QUEUE_INIT
;
181 button_flags_t flags
;
183 int len
; /* length including space and brackets */
189 { B_ENTER
, DEFPUSH_BUTTON
, N_("&Chdir"), 0, 0, NULL
, NULL
},
190 { B_AGAIN
, NORMAL_BUTTON
, N_("&Again"), 0, 0, NULL
, NULL
},
191 { B_STOP
, NORMAL_BUTTON
, N_("S&uspend"), 0, 0, NULL
, start_stop
},
192 { B_STOP
, NORMAL_BUTTON
, N_("Con&tinue"), 0, 0, NULL
, NULL
},
193 { B_CANCEL
, NORMAL_BUTTON
, N_("&Quit"), 0, 0, NULL
, NULL
},
195 { B_PANELIZE
, NORMAL_BUTTON
, N_("Pane&lize"), 0, 0, NULL
, NULL
},
196 { B_VIEW
, NORMAL_BUTTON
, N_("&View - F3"), 0, 0, NULL
, find_do_view_file
},
197 { B_VIEW
, NORMAL_BUTTON
, N_("&Edit - F4"), 0, 0, NULL
, find_do_edit_file
}
201 static const size_t fbuts_num
= G_N_ELEMENTS (fbuts
);
202 static const size_t quit_button
= 4; /* index of "Quit" button */
204 static WListbox
*find_list
; /* Listbox with the file list */
206 static find_file_options_t options
= {
207 TRUE
, TRUE
, TRUE
, FALSE
, FALSE
,
208 TRUE
, FALSE
, FALSE
, FALSE
, FALSE
,
212 static char *in_start_dir
= INPUT_LAST_TEXT
;
214 static mc_search_t
*search_file_handle
= NULL
;
215 static mc_search_t
*search_content_handle
= NULL
;
217 /* --------------------------------------------------------------------------------------------- */
218 /*** file scope functions ************************************************************************/
219 /* --------------------------------------------------------------------------------------------- */
221 /* don't use max macro to avoid double str_term_width1() call in widget length caclulation */
227 return (a
> b
? a
: b
);
230 /* --------------------------------------------------------------------------------------------- */
233 parse_ignore_dirs (const char *ignore_dirs
)
235 size_t r
= 0, w
= 0; /* read and write iterators */
237 if (!options
.ignore_dirs_enable
|| ignore_dirs
== NULL
|| ignore_dirs
[0] == '\0')
240 find_ignore_dirs
= g_strsplit (ignore_dirs
, ":", -1);
242 /* Values like '/foo::/bar: produce holes in list.
243 * Find and remove them */
244 for (; find_ignore_dirs
[r
] != NULL
; r
++)
246 if (find_ignore_dirs
[r
][0] == '\0')
248 /* empty entry -- skip it */
249 MC_PTR_FREE (find_ignore_dirs
[r
]);
255 /* copy entry to the previous free array cell */
256 find_ignore_dirs
[w
] = find_ignore_dirs
[r
];
257 find_ignore_dirs
[r
] = NULL
;
260 canonicalize_pathname (find_ignore_dirs
[w
]);
261 if (find_ignore_dirs
[w
][0] != '\0')
264 MC_PTR_FREE (find_ignore_dirs
[w
]);
267 if (find_ignore_dirs
[0] == NULL
)
269 g_strfreev (find_ignore_dirs
);
270 find_ignore_dirs
= NULL
;
274 /* --------------------------------------------------------------------------------------------- */
277 find_load_options (void)
279 static gboolean loaded
= FALSE
;
286 options
.file_case_sens
=
287 mc_config_get_bool (mc_main_config
, "FindFile", "file_case_sens", TRUE
);
288 options
.file_pattern
=
289 mc_config_get_bool (mc_main_config
, "FindFile", "file_shell_pattern", TRUE
);
290 options
.find_recurs
= mc_config_get_bool (mc_main_config
, "FindFile", "file_find_recurs", TRUE
);
291 options
.skip_hidden
=
292 mc_config_get_bool (mc_main_config
, "FindFile", "file_skip_hidden", FALSE
);
293 options
.file_all_charsets
=
294 mc_config_get_bool (mc_main_config
, "FindFile", "file_all_charsets", FALSE
);
295 options
.content_case_sens
=
296 mc_config_get_bool (mc_main_config
, "FindFile", "content_case_sens", TRUE
);
297 options
.content_regexp
=
298 mc_config_get_bool (mc_main_config
, "FindFile", "content_regexp", FALSE
);
299 options
.content_first_hit
=
300 mc_config_get_bool (mc_main_config
, "FindFile", "content_first_hit", FALSE
);
301 options
.content_whole_words
=
302 mc_config_get_bool (mc_main_config
, "FindFile", "content_whole_words", FALSE
);
303 options
.content_all_charsets
=
304 mc_config_get_bool (mc_main_config
, "FindFile", "content_all_charsets", FALSE
);
305 options
.ignore_dirs_enable
=
306 mc_config_get_bool (mc_main_config
, "FindFile", "ignore_dirs_enable", TRUE
);
307 options
.ignore_dirs
= mc_config_get_string (mc_main_config
, "FindFile", "ignore_dirs", "");
309 if (options
.ignore_dirs
[0] == '\0')
310 MC_PTR_FREE (options
.ignore_dirs
);
313 /* --------------------------------------------------------------------------------------------- */
316 find_save_options (void)
318 mc_config_set_bool (mc_main_config
, "FindFile", "file_case_sens", options
.file_case_sens
);
319 mc_config_set_bool (mc_main_config
, "FindFile", "file_shell_pattern", options
.file_pattern
);
320 mc_config_set_bool (mc_main_config
, "FindFile", "file_find_recurs", options
.find_recurs
);
321 mc_config_set_bool (mc_main_config
, "FindFile", "file_skip_hidden", options
.skip_hidden
);
322 mc_config_set_bool (mc_main_config
, "FindFile", "file_all_charsets", options
.file_all_charsets
);
323 mc_config_set_bool (mc_main_config
, "FindFile", "content_case_sens", options
.content_case_sens
);
324 mc_config_set_bool (mc_main_config
, "FindFile", "content_regexp", options
.content_regexp
);
325 mc_config_set_bool (mc_main_config
, "FindFile", "content_first_hit", options
.content_first_hit
);
326 mc_config_set_bool (mc_main_config
, "FindFile", "content_whole_words",
327 options
.content_whole_words
);
328 mc_config_set_bool (mc_main_config
, "FindFile", "content_all_charsets",
329 options
.content_all_charsets
);
330 mc_config_set_bool (mc_main_config
, "FindFile", "ignore_dirs_enable",
331 options
.ignore_dirs_enable
);
332 mc_config_set_string (mc_main_config
, "FindFile", "ignore_dirs", options
.ignore_dirs
);
335 /* --------------------------------------------------------------------------------------------- */
338 add_to_list (const char *text
, void *data
)
340 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
, TRUE
);
343 /* --------------------------------------------------------------------------------------------- */
346 stop_idle (void *data
)
348 widget_want_idle (WIDGET (data
), FALSE
);
351 /* --------------------------------------------------------------------------------------------- */
354 status_update (const char *text
)
356 label_set_text (status_label
, text
);
359 /* --------------------------------------------------------------------------------------------- */
362 found_num_update (void)
364 char buffer
[BUF_TINY
];
365 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
366 label_set_text (found_num_label
, buffer
);
369 /* --------------------------------------------------------------------------------------------- */
372 get_list_info (char **file
, char **dir
, gsize
* start
, gsize
* end
)
374 find_match_location_t
*location
;
376 listbox_get_current (find_list
, file
, (void **) &location
);
377 if (location
!= NULL
)
380 *dir
= location
->dir
;
382 *start
= location
->start
;
384 *end
= location
->end
;
393 /* --------------------------------------------------------------------------------------------- */
394 /** check regular expression */
397 find_check_regexp (const char *r
)
400 gboolean regexp_ok
= FALSE
;
402 search
= mc_search_new (r
, NULL
);
406 search
->search_type
= MC_SEARCH_T_REGEX
;
407 regexp_ok
= mc_search_prepare (search
);
408 mc_search_free (search
);
414 /* --------------------------------------------------------------------------------------------- */
417 find_toggle_enable_params (void)
419 gboolean disable
= in_name
->buffer
[0] == '\0';
421 widget_disable (WIDGET (file_pattern_cbox
), disable
);
422 widget_disable (WIDGET (file_case_sens_cbox
), disable
);
424 widget_disable (WIDGET (file_all_charsets_cbox
), disable
);
428 /* --------------------------------------------------------------------------------------------- */
431 find_toggle_enable_content (void)
433 gboolean disable
= in_with
->buffer
[0] == '\0';
435 widget_disable (WIDGET (content_regexp_cbox
), disable
);
436 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
438 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
440 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
441 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
444 /* --------------------------------------------------------------------------------------------- */
446 * Callback for the parameter dialog.
447 * Validate regex, prevent closing the dialog if it's invalid.
451 find_parm_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
453 /* FIXME: HACK: use first draw of dialog to resolve widget state dependencies.
454 * Use this time moment to check input field content. We can't do that in MSG_INIT
455 * because history is not loaded yet.
456 * Probably, we want new MSG_ACTIVATE message as complement to MSG_VALIDATE one. Or
457 * we could name it MSG_POST_INIT.
459 * In one or two other places we use MSG_IDLE instead of MSG_DRAW for a similar
460 * purpose. We should remember to fix those places too when we introduce the new
463 static gboolean first_draw
= TRUE
;
465 WDialog
*h
= DIALOG (w
);
474 if (sender
== WIDGET (ignore_dirs_cbox
))
476 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
478 widget_disable (WIDGET (in_ignore
), disable
);
483 return MSG_NOT_HANDLED
;
486 if (h
->ret_value
!= B_ENTER
)
489 /* check filename regexp */
490 if (!(file_pattern_cbox
->state
& C_BOOL
)
491 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->buffer
))
493 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
494 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
495 dlg_select_widget (in_name
);
499 /* check content regexp */
500 if ((content_regexp_cbox
->state
& C_BOOL
) && (in_with
->buffer
[0] != '\0')
501 && !find_check_regexp (in_with
->buffer
))
503 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
504 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
505 dlg_select_widget (in_with
);
512 if (h
->current
->data
== in_name
)
513 find_toggle_enable_params ();
514 else if (h
->current
->data
== in_with
)
515 find_toggle_enable_content ();
521 find_toggle_enable_params ();
522 find_toggle_enable_content ();
526 /* fall through to call MSG_DRAW default handler */
529 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
533 /* --------------------------------------------------------------------------------------------- */
535 * find_parameters: gets information from the user
537 * If the return value is TRUE, then the following holds:
539 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
540 * They are newly allocated strings and must be freed when uneeded.
542 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
543 * of start_dir (which is absolute). It is used to get a relative pats of find results.
547 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
548 char **ignore_dirs
, char **pattern
, char **content
)
550 /* Size of the find parameters window */
552 const int lines
= 18;
554 const int lines
= 17;
558 gboolean return_value
;
561 const char *file_name_label
= N_("File name:");
562 const char *file_recurs_label
= N_("&Find recursively");
563 const char *file_pattern_label
= N_("&Using shell patterns");
565 const char *file_all_charsets_label
= N_("&All charsets");
567 const char *file_case_label
= N_("Cas&e sensitive");
568 const char *file_skip_hidden_label
= N_("S&kip hidden");
571 const char *content_content_label
= N_("Content:");
572 const char *content_use_label
= N_("Sea&rch for content");
573 const char *content_regexp_label
= N_("Re&gular expression");
574 const char *content_case_label
= N_("Case sens&itive");
576 const char *content_all_charsets_label
= N_("A&ll charsets");
578 const char *content_whole_words_label
= N_("&Whole words");
579 const char *content_first_hit_label
= N_("Fir&st hit");
581 const char *buts
[] = { N_("&Tree"), N_("&OK"), N_("&Cancel") };
593 file_name_label
= _(file_name_label
);
594 file_recurs_label
= _(file_recurs_label
);
595 file_pattern_label
= _(file_pattern_label
);
597 file_all_charsets_label
= _(file_all_charsets_label
);
599 file_case_label
= _(file_case_label
);
600 file_skip_hidden_label
= _(file_skip_hidden_label
);
603 content_content_label
= _(content_content_label
);
604 content_use_label
= _(content_use_label
);
605 content_regexp_label
= _(content_regexp_label
);
606 content_case_label
= _(content_case_label
);
608 content_all_charsets_label
= _(content_all_charsets_label
);
610 content_whole_words_label
= _(content_whole_words_label
);
611 content_first_hit_label
= _(content_first_hit_label
);
613 for (i
= 0; i
< G_N_ELEMENTS (buts
); i
++)
614 buts
[i
] = _(buts
[i
]);
616 #endif /* ENABLE_NLS */
618 /* caclulate dialog width */
621 cw
= str_term_width1 (file_name_label
);
622 cw
= max (cw
, str_term_width1 (file_recurs_label
) + 4);
623 cw
= max (cw
, str_term_width1 (file_pattern_label
) + 4);
625 cw
= max (cw
, str_term_width1 (file_all_charsets_label
) + 4);
627 cw
= max (cw
, str_term_width1 (file_case_label
) + 4);
628 cw
= max (cw
, str_term_width1 (file_skip_hidden_label
) + 4);
630 cw
= max (cw
, str_term_width1 (content_content_label
) + 4);
631 cw
= max (cw
, str_term_width1 (content_use_label
) + 4);
632 cw
= max (cw
, str_term_width1 (content_regexp_label
) + 4);
633 cw
= max (cw
, str_term_width1 (content_case_label
) + 4);
635 cw
= max (cw
, str_term_width1 (content_all_charsets_label
) + 4);
637 cw
= max (cw
, str_term_width1 (content_whole_words_label
) + 4);
638 cw
= max (cw
, str_term_width1 (content_first_hit_label
) + 4);
641 b0
= str_term_width1 (buts
[0]) + 3;
642 b1
= str_term_width1 (buts
[1]) + 5; /* default button */
643 b2
= str_term_width1 (buts
[2]) + 3;
646 cols
= max (cols
, max (b12
, cw
* 2 + 1) + 6);
648 find_load_options ();
650 if (in_start_dir
== NULL
)
651 in_start_dir
= g_strdup (".");
654 dlg_create (TRUE
, 0, 0, lines
, cols
, dialog_colors
, find_parm_callback
, NULL
, "[Find File]",
655 _("Find File"), DLG_CENTER
);
662 add_widget (find_dlg
, label_new (y1
++, x1
, _("Start at:")));
664 input_new (y1
, x1
, input_colors
, cols
- b0
- 7, in_start_dir
, "start",
665 INPUT_COMPLETE_CD
| INPUT_COMPLETE_FILENAMES
);
666 add_widget (find_dlg
, in_start
);
668 add_widget (find_dlg
, button_new (y1
++, cols
- b0
- 3, B_TREE
, NORMAL_BUTTON
, buts
[0], NULL
));
671 check_new (y1
++, x1
, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
672 add_widget (find_dlg
, ignore_dirs_cbox
);
675 input_new (y1
++, x1
, input_colors
, cols
- 6,
676 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "", "ignoredirs",
677 INPUT_COMPLETE_CD
| INPUT_COMPLETE_FILENAMES
);
678 add_widget (find_dlg
, in_ignore
);
680 add_widget (find_dlg
, hline_new (y1
++, -1, -1));
684 /* Start 1st column */
685 add_widget (find_dlg
, label_new (y1
++, x1
, file_name_label
));
687 input_new (y1
++, x1
, input_colors
, cw
, INPUT_LAST_TEXT
, "name",
688 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
689 add_widget (find_dlg
, in_name
);
691 /* Start 2nd column */
692 content_label
= label_new (y2
++, x2
, content_content_label
);
693 add_widget (find_dlg
, content_label
);
695 input_new (y2
++, x2
, input_colors
, cw
, INPUT_LAST_TEXT
,
696 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_NONE
);
697 in_with
->label
= content_label
;
698 add_widget (find_dlg
, in_with
);
700 /* Continue 1st column */
701 recursively_cbox
= check_new (y1
++, x1
, options
.find_recurs
, file_recurs_label
);
702 add_widget (find_dlg
, recursively_cbox
);
704 file_pattern_cbox
= check_new (y1
++, x1
, options
.file_pattern
, file_pattern_label
);
705 add_widget (find_dlg
, file_pattern_cbox
);
707 file_case_sens_cbox
= check_new (y1
++, x1
, options
.file_case_sens
, file_case_label
);
708 add_widget (find_dlg
, file_case_sens_cbox
);
711 file_all_charsets_cbox
=
712 check_new (y1
++, x1
, options
.file_all_charsets
, file_all_charsets_label
);
713 add_widget (find_dlg
, file_all_charsets_cbox
);
716 skip_hidden_cbox
= check_new (y1
++, x1
, options
.skip_hidden
, file_skip_hidden_label
);
717 add_widget (find_dlg
, skip_hidden_cbox
);
719 /* Continue 2nd column */
720 content_whole_words_cbox
=
721 check_new (y2
++, x2
, options
.content_whole_words
, content_whole_words_label
);
722 add_widget (find_dlg
, content_whole_words_cbox
);
724 content_regexp_cbox
= check_new (y2
++, x2
, options
.content_regexp
, content_regexp_label
);
725 add_widget (find_dlg
, content_regexp_cbox
);
727 content_case_sens_cbox
= check_new (y2
++, x2
, options
.content_case_sens
, content_case_label
);
728 add_widget (find_dlg
, content_case_sens_cbox
);
731 content_all_charsets_cbox
=
732 check_new (y2
++, x2
, options
.content_all_charsets
, content_all_charsets_label
);
733 add_widget (find_dlg
, content_all_charsets_cbox
);
736 content_first_hit_cbox
=
737 check_new (y2
++, x2
, options
.content_first_hit
, content_first_hit_label
);
738 add_widget (find_dlg
, content_first_hit_cbox
);
742 x1
= (cols
- b12
) / 2;
743 add_widget (find_dlg
, hline_new (y1
++, -1, -1));
744 add_widget (find_dlg
, button_new (y1
, x1
, B_ENTER
, DEFPUSH_BUTTON
, buts
[1], NULL
));
745 add_widget (find_dlg
, button_new (y1
, x1
+ b1
+ 1, B_CANCEL
, NORMAL_BUTTON
, buts
[2], NULL
));
748 dlg_select_widget (in_name
);
750 switch (dlg_run (find_dlg
))
753 return_value
= FALSE
;
760 temp_dir
= in_start
->buffer
;
761 if (*temp_dir
== '\0' || DIR_IS_DOT (temp_dir
))
762 temp_dir
= g_strdup (vfs_path_as_str (current_panel
->cwd_vpath
));
764 temp_dir
= g_strdup (temp_dir
);
766 if (in_start_dir
!= INPUT_LAST_TEXT
)
767 g_free (in_start_dir
);
768 in_start_dir
= tree_box (temp_dir
);
769 if (in_start_dir
== NULL
)
770 in_start_dir
= temp_dir
;
774 input_assign_text (in_start
, in_start_dir
);
776 /* Warning: Dreadful goto */
785 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
786 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
788 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
789 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
790 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
791 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
792 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
793 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
794 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
795 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
796 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
797 g_free (options
.ignore_dirs
);
798 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
800 *content
= in_with
->buffer
[0] != '\0' ? g_strdup (in_with
->buffer
) : NULL
;
801 if (in_name
->buffer
[0] != '\0')
802 *pattern
= g_strdup (in_name
->buffer
);
804 *pattern
= g_strdup (options
.file_pattern
? "*" : ".*");
805 *start_dir
= !input_is_empty (in_start
) ? in_start
->buffer
: (char *) ".";
806 if (in_start_dir
!= INPUT_LAST_TEXT
)
807 g_free (in_start_dir
);
808 in_start_dir
= g_strdup (*start_dir
);
810 s
= tilde_expand (*start_dir
);
811 canonicalize_pathname (s
);
815 *start_dir
= g_strdup (vfs_path_as_str (current_panel
->cwd_vpath
));
816 /* FIXME: is current_panel->cwd_vpath canonicalized? */
817 /* relative paths will be used in panelization */
818 *start_dir_len
= (ssize_t
) strlen (*start_dir
);
821 else if (g_path_is_absolute (s
))
828 /* relative paths will be used in panelization */
830 mc_build_filename (vfs_path_as_str (current_panel
->cwd_vpath
), s
,
832 *start_dir_len
= (ssize_t
) strlen (vfs_path_as_str (current_panel
->cwd_vpath
));
836 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
837 || DIR_IS_DOT (in_ignore
->buffer
))
840 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
842 find_save_options ();
848 dlg_destroy (find_dlg
);
853 /* --------------------------------------------------------------------------------------------- */
856 push_directory (vfs_path_t
* dir
)
858 g_queue_push_head (&dir_queue
, (void *) dir
);
861 /* --------------------------------------------------------------------------------------------- */
863 static inline vfs_path_t
*
866 return (vfs_path_t
*) g_queue_pop_tail (&dir_queue
);
869 /* --------------------------------------------------------------------------------------------- */
870 /** Remove all the items from the stack */
875 g_queue_foreach (&dir_queue
, (GFunc
) vfs_path_free
, NULL
);
876 g_queue_clear (&dir_queue
);
879 /* --------------------------------------------------------------------------------------------- */
882 insert_file (const char *dir
, const char *file
, gsize start
, gsize end
)
884 char *tmp_name
= NULL
;
885 static char *dirname
= NULL
;
886 find_match_location_t
*location
;
888 while (IS_PATH_SEP (dir
[0]) && IS_PATH_SEP (dir
[1]))
893 if (strcmp (old_dir
, dir
))
896 old_dir
= g_strdup (dir
);
897 dirname
= add_to_list (dir
, NULL
);
902 old_dir
= g_strdup (dir
);
903 dirname
= add_to_list (dir
, NULL
);
906 tmp_name
= g_strdup_printf (" %s", file
);
907 location
= g_malloc (sizeof (*location
));
908 location
->dir
= dirname
;
909 location
->start
= start
;
911 add_to_list (tmp_name
, location
);
915 /* --------------------------------------------------------------------------------------------- */
918 find_add_match (const char *dir
, const char *file
, gsize start
, gsize end
)
920 insert_file (dir
, file
, start
, end
);
924 listbox_select_first (find_list
);
925 widget_redraw (WIDGET (find_list
));
931 /* --------------------------------------------------------------------------------------------- */
933 static FindProgressStatus
934 check_find_events (WDialog
* h
)
940 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
943 dlg_process_event (h
, c
, &event
);
944 if (h
->ret_value
== B_ENTER
945 || h
->ret_value
== B_CANCEL
|| h
->ret_value
== B_AGAIN
|| h
->ret_value
== B_PANELIZE
)
947 /* dialog terminated */
950 if ((WIDGET (h
)->options
& W_WANT_IDLE
) == 0)
952 /* searching suspended */
960 /* --------------------------------------------------------------------------------------------- */
964 * Search the content_pattern string in the DIRECTORY/FILE.
965 * It will add the found entries to the find listbox.
967 * returns FALSE if do_search should look for another file
968 * TRUE if do_search should exit and proceed to the event handler
972 search_content (WDialog
* h
, const char *directory
, const char *filename
)
975 char buffer
[BUF_4K
]; /* raw input buffer */
977 gboolean ret_val
= FALSE
;
981 suseconds_t useconds
;
982 gboolean status_updated
= FALSE
;
984 vpath
= vfs_path_build_filename (directory
, filename
, (char *) NULL
);
986 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
988 vfs_path_free (vpath
);
992 file_fd
= mc_open (vpath
, O_RDONLY
);
993 vfs_path_free (vpath
);
998 /* get time elapsed from last refresh */
999 if (gettimeofday (&tv
, NULL
) == -1)
1005 seconds
= tv
.tv_sec
- last_refresh
.tv_sec
;
1006 useconds
= tv
.tv_usec
- last_refresh
.tv_usec
;
1010 useconds
+= G_USEC_PER_SEC
;
1013 if (s
.st_size
>= MIN_REFRESH_FILE_SIZE
|| seconds
> 0 || useconds
> MAX_REFRESH_INTERVAL
)
1015 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), filename
);
1016 status_update (str_trunc (buffer
, WIDGET (h
)->cols
- 8));
1019 status_updated
= TRUE
;
1022 tty_enable_interrupt_key ();
1023 tty_got_interrupt ();
1029 off_t off
= 0; /* file_fd's offset corresponding to strbuf[0] */
1030 gboolean found
= FALSE
;
1033 char result
[BUF_MEDIUM
];
1034 char *strbuf
= NULL
; /* buffer for fetched string */
1035 int strbuf_size
= 0;
1036 int i
= -1; /* compensate for a newline we'll add when we first enter the loop */
1040 /* We've been previously suspended, start from the previous position */
1051 off
+= i
+ 1; /* the previous line, plus a newline character */
1054 /* read to buffer and get line from there */
1060 n_read
= mc_read (file_fd
, buffer
, sizeof (buffer
));
1068 /* skip possible leading zero(s) */
1077 if (i
>= strbuf_size
- 1)
1080 strbuf
= g_realloc (strbuf
, strbuf_size
);
1095 /* if (ch == '\n'): do not search in empty strings */
1101 if (!found
/* Search in binary line once */
1102 && mc_search_run (search_content_handle
, (const void *) strbuf
, 0, i
, &found_len
))
1104 if (!status_updated
)
1106 /* if we add results for a file, we have to ensure that
1107 name of this file is shown in status bar */
1108 g_snprintf (result
, sizeof (result
), _("Grepping in %s"), filename
);
1109 status_update (str_trunc (result
, WIDGET (h
)->cols
- 8));
1112 status_updated
= TRUE
;
1115 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1116 found_start
= off
+ search_content_handle
->normal_offset
+ 1; /* off by one: ticket 3280 */
1117 find_add_match (directory
, result
, found_start
, found_start
+ found_len
);
1121 if (found
&& options
.content_first_hit
)
1131 if ((line
& 0xff) == 0)
1133 FindProgressStatus res
;
1134 res
= check_find_events (h
);
1158 tty_disable_interrupt_key ();
1163 /* --------------------------------------------------------------------------------------------- */
1166 If dir is absolute, this means we're within dir and searching file here.
1167 If dir is relative, this means we're going to add dir to the directory stack.
1170 find_ignore_dir_search (const char *dir
)
1172 if (find_ignore_dirs
!= NULL
)
1174 const size_t dlen
= strlen (dir
);
1175 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1179 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1181 const size_t ilen
= strlen (*ignore_dir
);
1182 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1184 /* ignore dir is too long -- skip it */
1188 /* handle absolute and relative paths */
1189 switch (iabs
| dabs
)
1191 case 0: /* both paths are relative */
1192 case 3: /* both paths are abolute */
1193 /* if ignore dir is not a path of dir -- skip it */
1194 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1196 /* be sure that ignore dir is not a part of dir like:
1197 ignore dir is "h", dir is "home" */
1198 if (dir
[ilen
] == '\0' || IS_PATH_SEP (dir
[ilen
]))
1202 case 1: /* dir is absolute, ignore_dir is relative */
1206 d
= strstr (dir
, *ignore_dir
);
1207 if (d
!= NULL
&& IS_PATH_SEP (d
[-1])
1208 && (d
[ilen
] == '\0' || IS_PATH_SEP (d
[ilen
])))
1212 case 2: /* dir is relative, ignore_dir is absolute */
1213 /* FIXME: skip this case */
1215 default: /* this cannot occurs */
1224 /* --------------------------------------------------------------------------------------------- */
1227 find_rotate_dash (const WDialog
* h
, gboolean show
)
1229 static size_t pos
= 0;
1230 static const char rotating_dash
[4] = "|/-\\";
1231 const Widget
*w
= CONST_WIDGET (h
);
1236 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1237 widget_move (h
, w
->lines
- 7, w
->cols
- 4);
1238 tty_print_char (show
? rotating_dash
[pos
] : ' ');
1239 pos
= (pos
+ 1) % sizeof (rotating_dash
);
1243 /* --------------------------------------------------------------------------------------------- */
1246 do_search (WDialog
* h
)
1248 static struct dirent
*dp
= NULL
;
1249 static DIR *dirp
= NULL
;
1250 static char *directory
= NULL
;
1251 struct stat tmp_stat
;
1253 unsigned short count
;
1256 { /* someone forces me to close dirp */
1262 MC_PTR_FREE (directory
);
1267 for (count
= 0; count
< 32; count
++)
1277 while (dirp
== NULL
)
1279 vfs_path_t
*tmp_vpath
= NULL
;
1281 tty_setcolor (REVERSE_COLOR
);
1285 tmp_vpath
= pop_directory ();
1286 if (tmp_vpath
== NULL
)
1289 if (ignore_count
== 0)
1290 status_update (_("Finished"));
1293 char msg
[BUF_SMALL
];
1294 g_snprintf (msg
, sizeof (msg
),
1295 ngettext ("Finished (ignored %zd directory)",
1296 "Finished (ignored %zd directories)",
1297 ignore_count
), ignore_count
);
1298 status_update (msg
);
1300 find_rotate_dash (h
, FALSE
);
1305 /* handle absolute ignore dirs here */
1309 ok
= find_ignore_dir_search (vfs_path_as_str (tmp_vpath
));
1314 vfs_path_free (tmp_vpath
);
1319 directory
= g_strdup (vfs_path_as_str (tmp_vpath
));
1323 char buffer
[BUF_MEDIUM
];
1325 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"), directory
);
1326 status_update (str_trunc (directory
, WIDGET (h
)->cols
- 8));
1329 dirp
= mc_opendir (tmp_vpath
);
1330 vfs_path_free (tmp_vpath
);
1331 } /* while (!dirp) */
1333 /* skip invalid filenames */
1334 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1338 if (DIR_IS_DOT (dp
->d_name
) || DIR_IS_DOTDOT (dp
->d_name
))
1340 /* skip invalid filenames */
1341 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1347 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1351 if (options
.find_recurs
&& (directory
!= NULL
))
1352 { /* Can directory be NULL ? */
1353 /* handle relative ignore dirs here */
1354 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1358 vfs_path_t
*tmp_vpath
;
1360 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1362 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1363 push_directory (tmp_vpath
);
1365 vfs_path_free (tmp_vpath
);
1369 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1370 0, strlen (dp
->d_name
), &bytes_found
);
1374 if (content_pattern
== NULL
)
1375 find_add_match (directory
, dp
->d_name
, 0, 0);
1376 else if (search_content (h
, directory
, dp
->d_name
))
1381 /* skip invalid filenames */
1382 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1386 find_rotate_dash (h
, TRUE
);
1391 /* --------------------------------------------------------------------------------------------- */
1394 init_find_vars (void)
1396 MC_PTR_FREE (old_dir
);
1400 /* Remove all the items from the stack */
1403 g_strfreev (find_ignore_dirs
);
1404 find_ignore_dirs
= NULL
;
1407 /* --------------------------------------------------------------------------------------------- */
1410 find_do_view_edit (gboolean unparsed_view
, gboolean edit
, char *dir
, char *file
, off_t search_start
,
1413 char *fullname
= NULL
;
1414 const char *filename
= NULL
;
1416 vfs_path_t
*fullname_vpath
;
1418 if (content_pattern
!= NULL
)
1420 filename
= strchr (file
+ 4, ':') + 1;
1421 line
= atoi (file
+ 4);
1425 filename
= file
+ 4;
1429 fullname_vpath
= vfs_path_build_filename (dir
, filename
, (char *) NULL
);
1431 edit_file_at_line (fullname_vpath
, use_internal_edit
!= 0, line
);
1433 view_file_at_line (fullname_vpath
, unparsed_view
, use_internal_view
!= 0, line
,
1434 search_start
, search_end
);
1435 vfs_path_free (fullname_vpath
);
1439 /* --------------------------------------------------------------------------------------------- */
1442 view_edit_currently_selected_file (gboolean unparsed_view
, gboolean edit
)
1445 find_match_location_t
*location
;
1447 listbox_get_current (find_list
, &text
, (void **) &location
);
1449 if ((text
== NULL
) || (location
== NULL
) || (location
->dir
== NULL
))
1450 return MSG_NOT_HANDLED
;
1452 find_do_view_edit (unparsed_view
, edit
, location
->dir
, text
, location
->start
, location
->end
);
1456 /* --------------------------------------------------------------------------------------------- */
1459 find_calc_button_locations (const WDialog
* h
, gboolean all_buttons
)
1461 const int cols
= CONST_WIDGET (h
)->cols
;
1465 l1
= fbuts
[0].len
+ fbuts
[1].len
+ fbuts
[is_start
? 3 : 2].len
+ fbuts
[4].len
+ 3;
1466 l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
+ 2;
1468 fbuts
[0].x
= (cols
- l1
) / 2;
1469 fbuts
[1].x
= fbuts
[0].x
+ fbuts
[0].len
+ 1;
1470 fbuts
[2].x
= fbuts
[1].x
+ fbuts
[1].len
+ 1;
1471 fbuts
[3].x
= fbuts
[2].x
;
1472 fbuts
[4].x
= fbuts
[2].x
+ fbuts
[is_start
? 3 : 2].len
+ 1;
1476 fbuts
[5].x
= (cols
- l2
) / 2;
1477 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ 1;
1478 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ 1;
1482 /* --------------------------------------------------------------------------------------------- */
1485 find_relocate_buttons (const WDialog
* h
, gboolean all_buttons
)
1489 find_calc_button_locations (h
, all_buttons
);
1491 for (i
= 0; i
< fbuts_num
; i
++)
1492 fbuts
[i
].button
->x
= CONST_WIDGET (h
)->x
+ fbuts
[i
].x
;
1495 /* --------------------------------------------------------------------------------------------- */
1498 find_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1500 WDialog
*h
= DIALOG (w
);
1505 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1507 gboolean unparsed_view
= (parm
== KEY_F (13));
1509 return view_edit_currently_selected_file (unparsed_view
, FALSE
);
1511 if (parm
== KEY_F (4))
1512 return view_edit_currently_selected_file (FALSE
, TRUE
);
1513 return MSG_NOT_HANDLED
;
1516 dlg_set_size (h
, LINES
- 4, COLS
- 16);
1517 find_relocate_buttons (h
, TRUE
);
1525 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
1529 /* --------------------------------------------------------------------------------------------- */
1530 /** Handles the Stop/Start button in the find window */
1533 start_stop (WButton
* button
, int action
)
1535 Widget
*w
= WIDGET (button
);
1540 widget_want_idle (WIDGET (find_dlg
), running
);
1541 is_start
= !is_start
;
1543 status_update (is_start
? _("Stopped") : _("Searching"));
1544 button_set_text (button
, fbuts
[is_start
? 3 : 2].text
);
1546 find_relocate_buttons (w
->owner
, FALSE
);
1547 dlg_redraw (w
->owner
);
1552 /* --------------------------------------------------------------------------------------------- */
1553 /** Handle view command, when invoked as a button */
1556 find_do_view_file (WButton
* button
, int action
)
1561 view_edit_currently_selected_file (FALSE
, FALSE
);
1565 /* --------------------------------------------------------------------------------------------- */
1566 /** Handle edit command, when invoked as a button */
1569 find_do_edit_file (WButton
* button
, int action
)
1574 view_edit_currently_selected_file (FALSE
, TRUE
);
1578 /* --------------------------------------------------------------------------------------------- */
1587 static gboolean i18n_flag
= FALSE
;
1591 for (i
= 0; i
< fbuts_num
; i
++)
1594 fbuts
[i
].text
= _(fbuts
[i
].text
);
1595 #endif /* ENABLE_NLS */
1596 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1597 if (fbuts
[i
].flags
== DEFPUSH_BUTTON
)
1608 dlg_create (TRUE
, 0, 0, lines
, cols
, dialog_colors
, find_callback
, NULL
, "[Find File]",
1609 _("Find File"), DLG_CENTER
);
1611 find_calc_button_locations (find_dlg
, TRUE
);
1614 find_list
= listbox_new (y
, 2, lines
- 10, cols
- 4, FALSE
, NULL
);
1615 add_widget_autopos (find_dlg
, find_list
, WPOS_KEEP_ALL
, NULL
);
1616 y
+= WIDGET (find_list
)->lines
;
1618 add_widget_autopos (find_dlg
, hline_new (y
++, -1, -1), WPOS_KEEP_BOTTOM
, NULL
);
1620 found_num_label
= label_new (y
++, 4, "");
1621 add_widget_autopos (find_dlg
, found_num_label
, WPOS_KEEP_BOTTOM
, NULL
);
1623 status_label
= label_new (y
++, 4, _("Searching"));
1624 add_widget_autopos (find_dlg
, status_label
, WPOS_KEEP_BOTTOM
, NULL
);
1626 add_widget_autopos (find_dlg
, hline_new (y
++, -1, -1), WPOS_KEEP_BOTTOM
, NULL
);
1628 for (i
= 0; i
< fbuts_num
; i
++)
1631 fbuts
[3].button
= fbuts
[2].button
;
1636 (y
, fbuts
[i
].x
, fbuts
[i
].ret_cmd
, fbuts
[i
].flags
, fbuts
[i
].text
,
1637 fbuts
[i
].callback
));
1638 add_widget_autopos (find_dlg
, fbuts
[i
].button
, WPOS_KEEP_BOTTOM
, NULL
);
1641 if (i
== quit_button
)
1645 dlg_select_widget (find_list
);
1648 /* --------------------------------------------------------------------------------------------- */
1655 search_content_handle
= mc_search_new (content_pattern
, NULL
);
1656 if (search_content_handle
)
1658 search_content_handle
->search_type
=
1659 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1660 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1661 search_content_handle
->whole_words
= options
.content_whole_words
;
1663 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1666 search_file_handle
= mc_search_new (find_pattern
, NULL
);
1667 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1668 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1670 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1672 search_file_handle
->is_entire_line
= options
.file_pattern
;
1676 widget_want_idle (WIDGET (find_dlg
), TRUE
);
1677 ret
= dlg_run (find_dlg
);
1679 mc_search_free (search_file_handle
);
1680 search_file_handle
= NULL
;
1681 mc_search_free (search_content_handle
);
1682 search_content_handle
= NULL
;
1687 /* --------------------------------------------------------------------------------------------- */
1692 widget_want_idle (WIDGET (find_dlg
), FALSE
);
1693 dlg_destroy (find_dlg
);
1696 /* --------------------------------------------------------------------------------------------- */
1699 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1700 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1702 int return_value
= 0;
1703 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1707 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1708 find_pattern
= (char *) pattern
;
1710 content_pattern
= NULL
;
1711 if (content
!= NULL
&& str_is_valid_string (content
))
1712 content_pattern
= g_strdup (content
);
1715 parse_ignore_dirs (ignore_dirs
);
1716 push_directory (vfs_path_from_str (start_dir
));
1718 return_value
= run_process ();
1720 /* Clear variables */
1723 get_list_info (&file_tmp
, &dir_tmp
, NULL
, NULL
);
1726 *dirname
= g_strdup (dir_tmp
);
1728 *filename
= g_strdup (file_tmp
);
1730 if (return_value
== B_PANELIZE
&& *filename
)
1732 int link_to_dir
, stale_link
;
1736 dir_list
*list
= ¤t_panel
->dir
;
1739 dir_list_init (list
);
1741 for (i
= 0, entry
= listbox_get_first_link (find_list
); entry
!= NULL
;
1742 i
++, entry
= g_list_next (entry
))
1744 const char *lc_filename
= NULL
;
1745 WLEntry
*le
= LENTRY (entry
->data
);
1746 find_match_location_t
*location
= le
->data
;
1749 if ((le
->text
== NULL
) || (location
== NULL
) || (location
->dir
== NULL
))
1752 if (content_pattern
!= NULL
)
1753 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1755 lc_filename
= le
->text
+ 4;
1757 name
= mc_build_filename (location
->dir
, lc_filename
, (char *) NULL
);
1758 /* skip initial start dir */
1759 if (start_dir_len
< 0)
1763 p
= name
+ (size_t) start_dir_len
;
1764 if (IS_PATH_SEP (*p
))
1768 if (!handle_path (p
, &st
, &link_to_dir
, &stale_link
))
1773 /* Need to grow the *list? */
1774 if (list
->len
== list
->size
&& !dir_list_grow (list
, DIR_LIST_RESIZE_STEP
))
1780 /* don't add files more than once to the panel */
1781 if (content_pattern
!= NULL
&& list
->len
!= 0
1782 && strcmp (list
->list
[list
->len
- 1].fname
, p
) == 0)
1788 if (list
->len
== 0) /* first turn i.e clean old list */
1789 panel_clean_dir (current_panel
);
1790 list
->list
[list
->len
].fnamelen
= strlen (p
);
1791 list
->list
[list
->len
].fname
= g_strndup (p
, list
->list
[list
->len
].fnamelen
);
1792 list
->list
[list
->len
].f
.marked
= 0;
1793 list
->list
[list
->len
].f
.link_to_dir
= link_to_dir
;
1794 list
->list
[list
->len
].f
.stale_link
= stale_link
;
1795 list
->list
[list
->len
].f
.dir_size_computed
= 0;
1796 list
->list
[list
->len
].st
= st
;
1797 list
->list
[list
->len
].sort_key
= NULL
;
1798 list
->list
[list
->len
].second_sort_key
= NULL
;
1801 if ((list
->len
& 15) == 0)
1807 current_panel
->is_panelized
= TRUE
;
1810 if (start_dir_len
< 0)
1813 vfs_path_free (current_panel
->cwd_vpath
);
1814 current_panel
->cwd_vpath
= vfs_path_from_str (PATH_SEP_STR
);
1815 ret
= chdir (PATH_SEP_STR
);
1818 panelize_save_panel (current_panel
);
1822 g_free (content_pattern
);
1824 do_search (NULL
); /* force do_search to release resources */
1825 MC_PTR_FREE (old_dir
);
1826 rotate_dash (FALSE
);
1828 return return_value
;
1831 /* --------------------------------------------------------------------------------------------- */
1832 /*** public functions ****************************************************************************/
1833 /* --------------------------------------------------------------------------------------------- */
1838 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1839 ssize_t start_dir_len
;
1841 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1843 char *filename
= NULL
, *dirname
= NULL
;
1846 if (pattern
[0] != '\0')
1848 last_refresh
.tv_sec
= 0;
1849 last_refresh
.tv_usec
= 0;
1852 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
,
1857 g_free (ignore_dirs
);
1862 if (dirname
!= NULL
)
1864 vfs_path_t
*dirname_vpath
;
1866 dirname_vpath
= vfs_path_from_str (dirname
);
1867 do_cd (dirname_vpath
, cd_exact
);
1868 vfs_path_free (dirname_vpath
);
1869 if (filename
!= NULL
)
1870 try_to_select (current_panel
,
1871 filename
+ (content
!= NULL
1872 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1874 else if (filename
!= NULL
)
1876 vfs_path_t
*filename_vpath
;
1878 filename_vpath
= vfs_path_from_str (filename
);
1879 do_cd (filename_vpath
, cd_exact
);
1880 vfs_path_free (filename_vpath
);
1888 if (v
== B_ENTER
|| v
== B_CANCEL
)
1891 if (v
== B_PANELIZE
)
1893 panel_re_sort (current_panel
);
1894 try_to_select (current_panel
, NULL
);
1900 /* --------------------------------------------------------------------------------------------- */