2 Find file command for the Midnight Commander
4 Copyright (C) 1995-2016
5 Free Software Foundation, Inc.
9 Slava Zanko <slavazanko@gmail.com>, 2013
10 Andrew Borodin <aborodin@vmail.ru>, 2013
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 * \brief Source: Find file command
41 #include "lib/global.h"
43 #include "lib/tty/tty.h"
44 #include "lib/tty/key.h"
46 #include "lib/search.h"
47 #include "lib/mcconfig.h"
48 #include "lib/vfs/vfs.h"
49 #include "lib/strutil.h"
50 #include "lib/widget.h"
51 #include "lib/util.h" /* canonicalize_pathname() */
53 #include "src/setup.h" /* verbose */
54 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
57 #include "cmd.h" /* view_file_at_line() */
58 #include "midnight.h" /* current_panel */
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 #define MAX_REFRESH_INTERVAL (G_USEC_PER_SEC / 20) /* 50 ms */
69 #define MIN_REFRESH_FILE_SIZE (256 * 1024) /* 256 KB */
71 /*** file scope type declarations ****************************************************************/
73 /* A couple of extra messages we need */
90 /* find file options */
93 /* file name options */
94 gboolean file_case_sens
;
95 gboolean file_pattern
;
98 gboolean file_all_charsets
;
100 /* file content options */
101 gboolean content_case_sens
;
102 gboolean content_regexp
;
103 gboolean content_first_hit
;
104 gboolean content_whole_words
;
105 gboolean content_all_charsets
;
107 /* whether use ignore dirs or not */
108 gboolean ignore_dirs_enable
;
109 /* list of directories to be ignored, separated by ':' */
111 } find_file_options_t
;
118 } find_match_location_t
;
120 /*** file scope variables ************************************************************************/
122 /* button callbacks */
123 static int start_stop (WButton
* button
, int action
);
124 static int find_do_view_file (WButton
* button
, int action
);
125 static int find_do_edit_file (WButton
* button
, int action
);
127 /* Parsed ignore dirs */
128 static char **find_ignore_dirs
= NULL
;
130 /* static variables to remember find parameters */
131 static WInput
*in_start
; /* Start path */
132 static WInput
*in_name
; /* Filename */
133 static WInput
*in_with
; /* Text */
134 static WInput
*in_ignore
;
135 static WLabel
*content_label
; /* 'Content:' label */
136 static WCheck
*file_case_sens_cbox
; /* "case sensitive" checkbox */
137 static WCheck
*file_pattern_cbox
; /* File name is glob or regexp */
138 static WCheck
*recursively_cbox
;
139 static WCheck
*skip_hidden_cbox
;
140 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
141 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
142 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
143 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
145 static WCheck
*file_all_charsets_cbox
;
146 static WCheck
*content_all_charsets_cbox
;
148 static WCheck
*ignore_dirs_cbox
;
150 static gboolean running
= FALSE
; /* nice flag */
151 static char *find_pattern
= NULL
; /* Pattern to search */
152 static char *content_pattern
= NULL
; /* pattern to search inside files; if
153 content_regexp_flag is true, it contains the
154 regex pattern, else the search string. */
155 static unsigned long matches
; /* Number of matches */
156 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
157 static char *old_dir
= NULL
;
159 static struct timeval last_refresh
;
161 /* Where did we stop */
162 static gboolean resuming
;
163 static int last_line
;
165 static off_t last_off
;
168 static size_t ignore_count
= 0;
170 static WDialog
*find_dlg
; /* The dialog */
171 static WLabel
*status_label
; /* Finished, Searching etc. */
172 static WLabel
*found_num_label
; /* Number of found items */
174 /* This keeps track of the directory stack */
175 static GQueue dir_queue
= G_QUEUE_INIT
;
181 button_flags_t flags
;
183 int len
; /* length including space and brackets */
189 { B_ENTER
, DEFPUSH_BUTTON
, N_("&Chdir"), 0, 0, NULL
, NULL
},
190 { B_AGAIN
, NORMAL_BUTTON
, N_("&Again"), 0, 0, NULL
, NULL
},
191 { B_STOP
, NORMAL_BUTTON
, N_("S&uspend"), 0, 0, NULL
, start_stop
},
192 { B_STOP
, NORMAL_BUTTON
, N_("Con&tinue"), 0, 0, NULL
, NULL
},
193 { B_CANCEL
, NORMAL_BUTTON
, N_("&Quit"), 0, 0, NULL
, NULL
},
195 { B_PANELIZE
, NORMAL_BUTTON
, N_("Pane&lize"), 0, 0, NULL
, NULL
},
196 { B_VIEW
, NORMAL_BUTTON
, N_("&View - F3"), 0, 0, NULL
, find_do_view_file
},
197 { B_VIEW
, NORMAL_BUTTON
, N_("&Edit - F4"), 0, 0, NULL
, find_do_edit_file
}
201 static const size_t fbuts_num
= G_N_ELEMENTS (fbuts
);
202 static const size_t quit_button
= 4; /* index of "Quit" button */
204 static WListbox
*find_list
; /* Listbox with the file list */
206 static find_file_options_t options
= {
207 TRUE
, TRUE
, TRUE
, FALSE
, FALSE
,
208 TRUE
, FALSE
, FALSE
, FALSE
, FALSE
,
212 static char *in_start_dir
= INPUT_LAST_TEXT
;
214 static mc_search_t
*search_file_handle
= NULL
;
215 static mc_search_t
*search_content_handle
= NULL
;
217 /* --------------------------------------------------------------------------------------------- */
218 /*** file scope functions ************************************************************************/
219 /* --------------------------------------------------------------------------------------------- */
221 /* don't use max macro to avoid double str_term_width1() call in widget length caclulation */
227 return (a
> b
? a
: b
);
230 /* --------------------------------------------------------------------------------------------- */
233 parse_ignore_dirs (const char *ignore_dirs
)
235 size_t r
= 0, w
= 0; /* read and write iterators */
237 if (!options
.ignore_dirs_enable
|| ignore_dirs
== NULL
|| ignore_dirs
[0] == '\0')
240 find_ignore_dirs
= g_strsplit (ignore_dirs
, ":", -1);
242 /* Values like '/foo::/bar: produce holes in list.
243 * Find and remove them */
244 for (; find_ignore_dirs
[r
] != NULL
; r
++)
246 if (find_ignore_dirs
[r
][0] == '\0')
248 /* empty entry -- skip it */
249 MC_PTR_FREE (find_ignore_dirs
[r
]);
255 /* copy entry to the previous free array cell */
256 find_ignore_dirs
[w
] = find_ignore_dirs
[r
];
257 find_ignore_dirs
[r
] = NULL
;
260 canonicalize_pathname (find_ignore_dirs
[w
]);
261 if (find_ignore_dirs
[w
][0] != '\0')
264 MC_PTR_FREE (find_ignore_dirs
[w
]);
267 if (find_ignore_dirs
[0] == NULL
)
269 g_strfreev (find_ignore_dirs
);
270 find_ignore_dirs
= NULL
;
274 /* --------------------------------------------------------------------------------------------- */
277 find_load_options (void)
279 static gboolean loaded
= FALSE
;
286 options
.file_case_sens
=
287 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_case_sens", TRUE
);
288 options
.file_pattern
=
289 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_shell_pattern", TRUE
);
290 options
.find_recurs
=
291 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_find_recurs", TRUE
);
292 options
.skip_hidden
=
293 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_skip_hidden", FALSE
);
294 options
.file_all_charsets
=
295 mc_config_get_bool (mc_global
.main_config
, "FindFile", "file_all_charsets", FALSE
);
296 options
.content_case_sens
=
297 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_case_sens", TRUE
);
298 options
.content_regexp
=
299 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_regexp", FALSE
);
300 options
.content_first_hit
=
301 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_first_hit", FALSE
);
302 options
.content_whole_words
=
303 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_whole_words", FALSE
);
304 options
.content_all_charsets
=
305 mc_config_get_bool (mc_global
.main_config
, "FindFile", "content_all_charsets", FALSE
);
306 options
.ignore_dirs_enable
=
307 mc_config_get_bool (mc_global
.main_config
, "FindFile", "ignore_dirs_enable", TRUE
);
308 options
.ignore_dirs
=
309 mc_config_get_string (mc_global
.main_config
, "FindFile", "ignore_dirs", "");
311 if (options
.ignore_dirs
[0] == '\0')
312 MC_PTR_FREE (options
.ignore_dirs
);
315 /* --------------------------------------------------------------------------------------------- */
318 find_save_options (void)
320 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_case_sens",
321 options
.file_case_sens
);
322 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_shell_pattern",
323 options
.file_pattern
);
324 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_find_recurs", options
.find_recurs
);
325 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_skip_hidden", options
.skip_hidden
);
326 mc_config_set_bool (mc_global
.main_config
, "FindFile", "file_all_charsets",
327 options
.file_all_charsets
);
328 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_case_sens",
329 options
.content_case_sens
);
330 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_regexp",
331 options
.content_regexp
);
332 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_first_hit",
333 options
.content_first_hit
);
334 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_whole_words",
335 options
.content_whole_words
);
336 mc_config_set_bool (mc_global
.main_config
, "FindFile", "content_all_charsets",
337 options
.content_all_charsets
);
338 mc_config_set_bool (mc_global
.main_config
, "FindFile", "ignore_dirs_enable",
339 options
.ignore_dirs_enable
);
340 mc_config_set_string (mc_global
.main_config
, "FindFile", "ignore_dirs", options
.ignore_dirs
);
343 /* --------------------------------------------------------------------------------------------- */
346 add_to_list (const char *text
, void *data
)
348 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
, TRUE
);
351 /* --------------------------------------------------------------------------------------------- */
354 stop_idle (void *data
)
356 widget_idle (WIDGET (data
), FALSE
);
359 /* --------------------------------------------------------------------------------------------- */
362 status_update (const char *text
)
364 label_set_text (status_label
, text
);
367 /* --------------------------------------------------------------------------------------------- */
370 found_num_update (void)
372 char buffer
[BUF_TINY
];
373 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
374 label_set_text (found_num_label
, buffer
);
377 /* --------------------------------------------------------------------------------------------- */
380 get_list_info (char **file
, char **dir
, gsize
* start
, gsize
* end
)
382 find_match_location_t
*location
;
384 listbox_get_current (find_list
, file
, (void **) &location
);
385 if (location
!= NULL
)
388 *dir
= location
->dir
;
390 *start
= location
->start
;
392 *end
= location
->end
;
401 /* --------------------------------------------------------------------------------------------- */
402 /** check regular expression */
405 find_check_regexp (const char *r
)
408 gboolean regexp_ok
= FALSE
;
410 search
= mc_search_new (r
, NULL
);
414 search
->search_type
= MC_SEARCH_T_REGEX
;
415 regexp_ok
= mc_search_prepare (search
);
416 mc_search_free (search
);
422 /* --------------------------------------------------------------------------------------------- */
425 find_toggle_enable_params (void)
427 gboolean disable
= in_name
->buffer
[0] == '\0';
429 widget_disable (WIDGET (file_pattern_cbox
), disable
);
430 widget_disable (WIDGET (file_case_sens_cbox
), disable
);
432 widget_disable (WIDGET (file_all_charsets_cbox
), disable
);
436 /* --------------------------------------------------------------------------------------------- */
439 find_toggle_enable_content (void)
441 gboolean disable
= in_with
->buffer
[0] == '\0';
443 widget_disable (WIDGET (content_regexp_cbox
), disable
);
444 widget_disable (WIDGET (content_case_sens_cbox
), disable
);
446 widget_disable (WIDGET (content_all_charsets_cbox
), disable
);
448 widget_disable (WIDGET (content_whole_words_cbox
), disable
);
449 widget_disable (WIDGET (content_first_hit_cbox
), disable
);
452 /* --------------------------------------------------------------------------------------------- */
454 * Callback for the parameter dialog.
455 * Validate regex, prevent closing the dialog if it's invalid.
459 find_parm_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
461 /* FIXME: HACK: use first draw of dialog to resolve widget state dependencies.
462 * Use this time moment to check input field content. We can't do that in MSG_INIT
463 * because history is not loaded yet.
464 * Probably, we want new MSG_ACTIVATE message as complement to MSG_VALIDATE one. Or
465 * we could name it MSG_POST_INIT.
467 * In one or two other places we use MSG_IDLE instead of MSG_DRAW for a similar
468 * purpose. We should remember to fix those places too when we introduce the new
471 static gboolean first_draw
= TRUE
;
473 WDialog
*h
= DIALOG (w
);
482 if (sender
== WIDGET (ignore_dirs_cbox
))
484 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
486 widget_disable (WIDGET (in_ignore
), disable
);
491 return MSG_NOT_HANDLED
;
494 if (h
->ret_value
!= B_ENTER
)
497 /* check filename regexp */
498 if (!(file_pattern_cbox
->state
& C_BOOL
)
499 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->buffer
))
501 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
502 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
503 dlg_select_widget (in_name
);
507 /* check content regexp */
508 if ((content_regexp_cbox
->state
& C_BOOL
) && (in_with
->buffer
[0] != '\0')
509 && !find_check_regexp (in_with
->buffer
))
511 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
512 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
513 dlg_select_widget (in_with
);
520 if (h
->current
->data
== in_name
)
521 find_toggle_enable_params ();
522 else if (h
->current
->data
== in_with
)
523 find_toggle_enable_content ();
529 find_toggle_enable_params ();
530 find_toggle_enable_content ();
534 /* fall through to call MSG_DRAW default handler */
537 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
541 /* --------------------------------------------------------------------------------------------- */
543 * find_parameters: gets information from the user
545 * If the return value is TRUE, then the following holds:
547 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
548 * They are newly allocated strings and must be freed when uneeded.
550 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
551 * of start_dir (which is absolute). It is used to get a relative pats of find results.
555 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
556 char **ignore_dirs
, char **pattern
, char **content
)
558 /* Size of the find parameters window */
560 const int lines
= 18;
562 const int lines
= 17;
566 gboolean return_value
;
569 const char *file_name_label
= N_("File name:");
570 const char *file_recurs_label
= N_("&Find recursively");
571 const char *file_pattern_label
= N_("&Using shell patterns");
573 const char *file_all_charsets_label
= N_("&All charsets");
575 const char *file_case_label
= N_("Cas&e sensitive");
576 const char *file_skip_hidden_label
= N_("S&kip hidden");
579 const char *content_content_label
= N_("Content:");
580 const char *content_use_label
= N_("Sea&rch for content");
581 const char *content_regexp_label
= N_("Re&gular expression");
582 const char *content_case_label
= N_("Case sens&itive");
584 const char *content_all_charsets_label
= N_("A&ll charsets");
586 const char *content_whole_words_label
= N_("&Whole words");
587 const char *content_first_hit_label
= N_("Fir&st hit");
589 const char *buts
[] = { N_("&Tree"), N_("&OK"), N_("&Cancel") };
601 file_name_label
= _(file_name_label
);
602 file_recurs_label
= _(file_recurs_label
);
603 file_pattern_label
= _(file_pattern_label
);
605 file_all_charsets_label
= _(file_all_charsets_label
);
607 file_case_label
= _(file_case_label
);
608 file_skip_hidden_label
= _(file_skip_hidden_label
);
611 content_content_label
= _(content_content_label
);
612 content_use_label
= _(content_use_label
);
613 content_regexp_label
= _(content_regexp_label
);
614 content_case_label
= _(content_case_label
);
616 content_all_charsets_label
= _(content_all_charsets_label
);
618 content_whole_words_label
= _(content_whole_words_label
);
619 content_first_hit_label
= _(content_first_hit_label
);
621 for (i
= 0; i
< G_N_ELEMENTS (buts
); i
++)
622 buts
[i
] = _(buts
[i
]);
624 #endif /* ENABLE_NLS */
626 /* caclulate dialog width */
629 cw
= str_term_width1 (file_name_label
);
630 cw
= max (cw
, str_term_width1 (file_recurs_label
) + 4);
631 cw
= max (cw
, str_term_width1 (file_pattern_label
) + 4);
633 cw
= max (cw
, str_term_width1 (file_all_charsets_label
) + 4);
635 cw
= max (cw
, str_term_width1 (file_case_label
) + 4);
636 cw
= max (cw
, str_term_width1 (file_skip_hidden_label
) + 4);
638 cw
= max (cw
, str_term_width1 (content_content_label
) + 4);
639 cw
= max (cw
, str_term_width1 (content_use_label
) + 4);
640 cw
= max (cw
, str_term_width1 (content_regexp_label
) + 4);
641 cw
= max (cw
, str_term_width1 (content_case_label
) + 4);
643 cw
= max (cw
, str_term_width1 (content_all_charsets_label
) + 4);
645 cw
= max (cw
, str_term_width1 (content_whole_words_label
) + 4);
646 cw
= max (cw
, str_term_width1 (content_first_hit_label
) + 4);
649 b0
= str_term_width1 (buts
[0]) + 3;
650 b1
= str_term_width1 (buts
[1]) + 5; /* default button */
651 b2
= str_term_width1 (buts
[2]) + 3;
654 cols
= max (cols
, max (b12
, cw
* 2 + 1) + 6);
656 find_load_options ();
658 if (in_start_dir
== NULL
)
659 in_start_dir
= g_strdup (".");
662 dlg_create (TRUE
, 0, 0, lines
, cols
, dialog_colors
, find_parm_callback
, NULL
, "[Find File]",
663 _("Find File"), DLG_CENTER
);
670 add_widget (find_dlg
, label_new (y1
++, x1
, _("Start at:")));
672 input_new (y1
, x1
, input_colors
, cols
- b0
- 7, in_start_dir
, "start",
673 INPUT_COMPLETE_CD
| INPUT_COMPLETE_FILENAMES
);
674 add_widget (find_dlg
, in_start
);
676 add_widget (find_dlg
, button_new (y1
++, cols
- b0
- 3, B_TREE
, NORMAL_BUTTON
, buts
[0], NULL
));
679 check_new (y1
++, x1
, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
680 add_widget (find_dlg
, ignore_dirs_cbox
);
683 input_new (y1
++, x1
, input_colors
, cols
- 6,
684 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "", "ignoredirs",
685 INPUT_COMPLETE_CD
| INPUT_COMPLETE_FILENAMES
);
686 add_widget (find_dlg
, in_ignore
);
688 add_widget (find_dlg
, hline_new (y1
++, -1, -1));
692 /* Start 1st column */
693 add_widget (find_dlg
, label_new (y1
++, x1
, file_name_label
));
695 input_new (y1
++, x1
, input_colors
, cw
, INPUT_LAST_TEXT
, "name",
696 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
697 add_widget (find_dlg
, in_name
);
699 /* Start 2nd column */
700 content_label
= label_new (y2
++, x2
, content_content_label
);
701 add_widget (find_dlg
, content_label
);
703 input_new (y2
++, x2
, input_colors
, cw
, INPUT_LAST_TEXT
,
704 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_NONE
);
705 in_with
->label
= content_label
;
706 add_widget (find_dlg
, in_with
);
708 /* Continue 1st column */
709 recursively_cbox
= check_new (y1
++, x1
, options
.find_recurs
, file_recurs_label
);
710 add_widget (find_dlg
, recursively_cbox
);
712 file_pattern_cbox
= check_new (y1
++, x1
, options
.file_pattern
, file_pattern_label
);
713 add_widget (find_dlg
, file_pattern_cbox
);
715 file_case_sens_cbox
= check_new (y1
++, x1
, options
.file_case_sens
, file_case_label
);
716 add_widget (find_dlg
, file_case_sens_cbox
);
719 file_all_charsets_cbox
=
720 check_new (y1
++, x1
, options
.file_all_charsets
, file_all_charsets_label
);
721 add_widget (find_dlg
, file_all_charsets_cbox
);
724 skip_hidden_cbox
= check_new (y1
++, x1
, options
.skip_hidden
, file_skip_hidden_label
);
725 add_widget (find_dlg
, skip_hidden_cbox
);
727 /* Continue 2nd column */
728 content_whole_words_cbox
=
729 check_new (y2
++, x2
, options
.content_whole_words
, content_whole_words_label
);
730 add_widget (find_dlg
, content_whole_words_cbox
);
732 content_regexp_cbox
= check_new (y2
++, x2
, options
.content_regexp
, content_regexp_label
);
733 add_widget (find_dlg
, content_regexp_cbox
);
735 content_case_sens_cbox
= check_new (y2
++, x2
, options
.content_case_sens
, content_case_label
);
736 add_widget (find_dlg
, content_case_sens_cbox
);
739 content_all_charsets_cbox
=
740 check_new (y2
++, x2
, options
.content_all_charsets
, content_all_charsets_label
);
741 add_widget (find_dlg
, content_all_charsets_cbox
);
744 content_first_hit_cbox
=
745 check_new (y2
++, x2
, options
.content_first_hit
, content_first_hit_label
);
746 add_widget (find_dlg
, content_first_hit_cbox
);
750 x1
= (cols
- b12
) / 2;
751 add_widget (find_dlg
, hline_new (y1
++, -1, -1));
752 add_widget (find_dlg
, button_new (y1
, x1
, B_ENTER
, DEFPUSH_BUTTON
, buts
[1], NULL
));
753 add_widget (find_dlg
, button_new (y1
, x1
+ b1
+ 1, B_CANCEL
, NORMAL_BUTTON
, buts
[2], NULL
));
756 dlg_select_widget (in_name
);
758 switch (dlg_run (find_dlg
))
761 return_value
= FALSE
;
768 temp_dir
= in_start
->buffer
;
769 if (*temp_dir
== '\0' || DIR_IS_DOT (temp_dir
))
770 temp_dir
= g_strdup (vfs_path_as_str (current_panel
->cwd_vpath
));
772 temp_dir
= g_strdup (temp_dir
);
774 if (in_start_dir
!= INPUT_LAST_TEXT
)
775 g_free (in_start_dir
);
776 in_start_dir
= tree_box (temp_dir
);
777 if (in_start_dir
== NULL
)
778 in_start_dir
= temp_dir
;
782 input_assign_text (in_start
, in_start_dir
);
784 /* Warning: Dreadful goto */
793 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
794 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
796 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
797 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
798 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
799 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
800 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
801 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
802 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
803 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
804 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
805 g_free (options
.ignore_dirs
);
806 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
808 *content
= in_with
->buffer
[0] != '\0' ? g_strdup (in_with
->buffer
) : NULL
;
809 if (in_name
->buffer
[0] != '\0')
810 *pattern
= g_strdup (in_name
->buffer
);
812 *pattern
= g_strdup (options
.file_pattern
? "*" : ".*");
813 *start_dir
= !input_is_empty (in_start
) ? in_start
->buffer
: (char *) ".";
814 if (in_start_dir
!= INPUT_LAST_TEXT
)
815 g_free (in_start_dir
);
816 in_start_dir
= g_strdup (*start_dir
);
818 s
= tilde_expand (*start_dir
);
819 canonicalize_pathname (s
);
823 *start_dir
= g_strdup (vfs_path_as_str (current_panel
->cwd_vpath
));
824 /* FIXME: is current_panel->cwd_vpath canonicalized? */
825 /* relative paths will be used in panelization */
826 *start_dir_len
= (ssize_t
) strlen (*start_dir
);
829 else if (g_path_is_absolute (s
))
836 /* relative paths will be used in panelization */
838 mc_build_filename (vfs_path_as_str (current_panel
->cwd_vpath
), s
,
840 *start_dir_len
= (ssize_t
) strlen (vfs_path_as_str (current_panel
->cwd_vpath
));
844 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
845 || DIR_IS_DOT (in_ignore
->buffer
))
848 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
850 find_save_options ();
856 dlg_destroy (find_dlg
);
861 /* --------------------------------------------------------------------------------------------- */
864 push_directory (vfs_path_t
* dir
)
866 g_queue_push_head (&dir_queue
, (void *) dir
);
869 /* --------------------------------------------------------------------------------------------- */
871 static inline vfs_path_t
*
874 return (vfs_path_t
*) g_queue_pop_tail (&dir_queue
);
877 /* --------------------------------------------------------------------------------------------- */
878 /** Remove all the items from the stack */
883 g_queue_foreach (&dir_queue
, (GFunc
) vfs_path_free
, NULL
);
884 g_queue_clear (&dir_queue
);
887 /* --------------------------------------------------------------------------------------------- */
890 insert_file (const char *dir
, const char *file
, gsize start
, gsize end
)
892 char *tmp_name
= NULL
;
893 static char *dirname
= NULL
;
894 find_match_location_t
*location
;
896 while (IS_PATH_SEP (dir
[0]) && IS_PATH_SEP (dir
[1]))
901 if (strcmp (old_dir
, dir
))
904 old_dir
= g_strdup (dir
);
905 dirname
= add_to_list (dir
, NULL
);
910 old_dir
= g_strdup (dir
);
911 dirname
= add_to_list (dir
, NULL
);
914 tmp_name
= g_strdup_printf (" %s", file
);
915 location
= g_malloc (sizeof (*location
));
916 location
->dir
= dirname
;
917 location
->start
= start
;
919 add_to_list (tmp_name
, location
);
923 /* --------------------------------------------------------------------------------------------- */
926 find_add_match (const char *dir
, const char *file
, gsize start
, gsize end
)
928 insert_file (dir
, file
, start
, end
);
932 listbox_select_first (find_list
);
933 widget_redraw (WIDGET (find_list
));
939 /* --------------------------------------------------------------------------------------------- */
941 static FindProgressStatus
942 check_find_events (WDialog
* h
)
948 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
951 dlg_process_event (h
, c
, &event
);
952 if (h
->ret_value
== B_ENTER
953 || h
->ret_value
== B_CANCEL
|| h
->ret_value
== B_AGAIN
|| h
->ret_value
== B_PANELIZE
)
955 /* dialog terminated */
958 if (!widget_get_state (WIDGET (h
), WST_IDLE
))
960 /* searching suspended */
968 /* --------------------------------------------------------------------------------------------- */
972 * Search the content_pattern string in the DIRECTORY/FILE.
973 * It will add the found entries to the find listbox.
975 * returns FALSE if do_search should look for another file
976 * TRUE if do_search should exit and proceed to the event handler
980 search_content (WDialog
* h
, const char *directory
, const char *filename
)
983 char buffer
[BUF_4K
]; /* raw input buffer */
985 gboolean ret_val
= FALSE
;
989 suseconds_t useconds
;
990 gboolean status_updated
= FALSE
;
992 vpath
= vfs_path_build_filename (directory
, filename
, (char *) NULL
);
994 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
996 vfs_path_free (vpath
);
1000 file_fd
= mc_open (vpath
, O_RDONLY
);
1001 vfs_path_free (vpath
);
1006 /* get time elapsed from last refresh */
1007 if (gettimeofday (&tv
, NULL
) == -1)
1013 seconds
= tv
.tv_sec
- last_refresh
.tv_sec
;
1014 useconds
= tv
.tv_usec
- last_refresh
.tv_usec
;
1018 useconds
+= G_USEC_PER_SEC
;
1021 if (s
.st_size
>= MIN_REFRESH_FILE_SIZE
|| seconds
> 0 || useconds
> MAX_REFRESH_INTERVAL
)
1023 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), filename
);
1024 status_update (str_trunc (buffer
, WIDGET (h
)->cols
- 8));
1027 status_updated
= TRUE
;
1030 tty_enable_interrupt_key ();
1031 tty_got_interrupt ();
1037 off_t off
= 0; /* file_fd's offset corresponding to strbuf[0] */
1038 gboolean found
= FALSE
;
1041 char result
[BUF_MEDIUM
];
1042 char *strbuf
= NULL
; /* buffer for fetched string */
1043 int strbuf_size
= 0;
1044 int i
= -1; /* compensate for a newline we'll add when we first enter the loop */
1048 /* We've been previously suspended, start from the previous position */
1059 off
+= i
+ 1; /* the previous line, plus a newline character */
1062 /* read to buffer and get line from there */
1068 n_read
= mc_read (file_fd
, buffer
, sizeof (buffer
));
1076 /* skip possible leading zero(s) */
1085 if (i
>= strbuf_size
- 1)
1088 strbuf
= g_realloc (strbuf
, strbuf_size
);
1103 /* if (ch == '\n'): do not search in empty strings */
1109 if (!found
/* Search in binary line once */
1110 && mc_search_run (search_content_handle
, (const void *) strbuf
, 0, i
, &found_len
))
1112 if (!status_updated
)
1114 /* if we add results for a file, we have to ensure that
1115 name of this file is shown in status bar */
1116 g_snprintf (result
, sizeof (result
), _("Grepping in %s"), filename
);
1117 status_update (str_trunc (result
, WIDGET (h
)->cols
- 8));
1120 status_updated
= TRUE
;
1123 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1124 found_start
= off
+ search_content_handle
->normal_offset
+ 1; /* off by one: ticket 3280 */
1125 find_add_match (directory
, result
, found_start
, found_start
+ found_len
);
1129 if (found
&& options
.content_first_hit
)
1139 if ((line
& 0xff) == 0)
1141 FindProgressStatus res
;
1142 res
= check_find_events (h
);
1166 tty_disable_interrupt_key ();
1171 /* --------------------------------------------------------------------------------------------- */
1174 If dir is absolute, this means we're within dir and searching file here.
1175 If dir is relative, this means we're going to add dir to the directory stack.
1178 find_ignore_dir_search (const char *dir
)
1180 if (find_ignore_dirs
!= NULL
)
1182 const size_t dlen
= strlen (dir
);
1183 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1187 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1189 const size_t ilen
= strlen (*ignore_dir
);
1190 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1192 /* ignore dir is too long -- skip it */
1196 /* handle absolute and relative paths */
1197 switch (iabs
| dabs
)
1199 case 0: /* both paths are relative */
1200 case 3: /* both paths are abolute */
1201 /* if ignore dir is not a path of dir -- skip it */
1202 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1204 /* be sure that ignore dir is not a part of dir like:
1205 ignore dir is "h", dir is "home" */
1206 if (dir
[ilen
] == '\0' || IS_PATH_SEP (dir
[ilen
]))
1210 case 1: /* dir is absolute, ignore_dir is relative */
1214 d
= strstr (dir
, *ignore_dir
);
1215 if (d
!= NULL
&& IS_PATH_SEP (d
[-1])
1216 && (d
[ilen
] == '\0' || IS_PATH_SEP (d
[ilen
])))
1220 case 2: /* dir is relative, ignore_dir is absolute */
1221 /* FIXME: skip this case */
1223 default: /* this cannot occurs */
1232 /* --------------------------------------------------------------------------------------------- */
1235 find_rotate_dash (const WDialog
* h
, gboolean show
)
1237 static size_t pos
= 0;
1238 static const char rotating_dash
[4] = "|/-\\";
1239 const Widget
*w
= CONST_WIDGET (h
);
1244 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1245 widget_move (h
, w
->lines
- 7, w
->cols
- 4);
1246 tty_print_char (show
? rotating_dash
[pos
] : ' ');
1247 pos
= (pos
+ 1) % sizeof (rotating_dash
);
1251 /* --------------------------------------------------------------------------------------------- */
1254 do_search (WDialog
* h
)
1256 static struct dirent
*dp
= NULL
;
1257 static DIR *dirp
= NULL
;
1258 static char *directory
= NULL
;
1259 struct stat tmp_stat
;
1261 unsigned short count
;
1264 { /* someone forces me to close dirp */
1270 MC_PTR_FREE (directory
);
1275 for (count
= 0; count
< 32; count
++)
1285 while (dirp
== NULL
)
1287 vfs_path_t
*tmp_vpath
= NULL
;
1289 tty_setcolor (REVERSE_COLOR
);
1293 tmp_vpath
= pop_directory ();
1294 if (tmp_vpath
== NULL
)
1297 if (ignore_count
== 0)
1298 status_update (_("Finished"));
1301 char msg
[BUF_SMALL
];
1302 g_snprintf (msg
, sizeof (msg
),
1303 ngettext ("Finished (ignored %zd directory)",
1304 "Finished (ignored %zd directories)",
1305 ignore_count
), ignore_count
);
1306 status_update (msg
);
1308 find_rotate_dash (h
, FALSE
);
1313 /* handle absolute ignore dirs here */
1317 ok
= find_ignore_dir_search (vfs_path_as_str (tmp_vpath
));
1322 vfs_path_free (tmp_vpath
);
1327 directory
= g_strdup (vfs_path_as_str (tmp_vpath
));
1331 char buffer
[BUF_MEDIUM
];
1333 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"), directory
);
1334 status_update (str_trunc (directory
, WIDGET (h
)->cols
- 8));
1337 dirp
= mc_opendir (tmp_vpath
);
1338 vfs_path_free (tmp_vpath
);
1339 } /* while (!dirp) */
1341 /* skip invalid filenames */
1342 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1346 if (DIR_IS_DOT (dp
->d_name
) || DIR_IS_DOTDOT (dp
->d_name
))
1348 /* skip invalid filenames */
1349 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1355 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1359 if (options
.find_recurs
&& (directory
!= NULL
))
1360 { /* Can directory be NULL ? */
1361 /* handle relative ignore dirs here */
1362 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1366 vfs_path_t
*tmp_vpath
;
1368 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1370 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1371 push_directory (tmp_vpath
);
1373 vfs_path_free (tmp_vpath
);
1377 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1378 0, strlen (dp
->d_name
), &bytes_found
);
1382 if (content_pattern
== NULL
)
1383 find_add_match (directory
, dp
->d_name
, 0, 0);
1384 else if (search_content (h
, directory
, dp
->d_name
))
1389 /* skip invalid filenames */
1390 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1394 find_rotate_dash (h
, TRUE
);
1399 /* --------------------------------------------------------------------------------------------- */
1402 init_find_vars (void)
1404 MC_PTR_FREE (old_dir
);
1408 /* Remove all the items from the stack */
1411 g_strfreev (find_ignore_dirs
);
1412 find_ignore_dirs
= NULL
;
1415 /* --------------------------------------------------------------------------------------------- */
1418 find_do_view_edit (gboolean unparsed_view
, gboolean edit
, char *dir
, char *file
, off_t search_start
,
1421 char *fullname
= NULL
;
1422 const char *filename
= NULL
;
1424 vfs_path_t
*fullname_vpath
;
1426 if (content_pattern
!= NULL
)
1428 filename
= strchr (file
+ 4, ':') + 1;
1429 line
= atoi (file
+ 4);
1433 filename
= file
+ 4;
1437 fullname_vpath
= vfs_path_build_filename (dir
, filename
, (char *) NULL
);
1439 edit_file_at_line (fullname_vpath
, use_internal_edit
!= 0, line
);
1441 view_file_at_line (fullname_vpath
, unparsed_view
, use_internal_view
!= 0, line
,
1442 search_start
, search_end
);
1443 vfs_path_free (fullname_vpath
);
1447 /* --------------------------------------------------------------------------------------------- */
1450 view_edit_currently_selected_file (gboolean unparsed_view
, gboolean edit
)
1453 find_match_location_t
*location
;
1455 listbox_get_current (find_list
, &text
, (void **) &location
);
1457 if ((text
== NULL
) || (location
== NULL
) || (location
->dir
== NULL
))
1458 return MSG_NOT_HANDLED
;
1460 find_do_view_edit (unparsed_view
, edit
, location
->dir
, text
, location
->start
, location
->end
);
1464 /* --------------------------------------------------------------------------------------------- */
1467 find_calc_button_locations (const WDialog
* h
, gboolean all_buttons
)
1469 const int cols
= CONST_WIDGET (h
)->cols
;
1473 l1
= fbuts
[0].len
+ fbuts
[1].len
+ fbuts
[is_start
? 3 : 2].len
+ fbuts
[4].len
+ 3;
1474 l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
+ 2;
1476 fbuts
[0].x
= (cols
- l1
) / 2;
1477 fbuts
[1].x
= fbuts
[0].x
+ fbuts
[0].len
+ 1;
1478 fbuts
[2].x
= fbuts
[1].x
+ fbuts
[1].len
+ 1;
1479 fbuts
[3].x
= fbuts
[2].x
;
1480 fbuts
[4].x
= fbuts
[2].x
+ fbuts
[is_start
? 3 : 2].len
+ 1;
1484 fbuts
[5].x
= (cols
- l2
) / 2;
1485 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ 1;
1486 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ 1;
1490 /* --------------------------------------------------------------------------------------------- */
1493 find_relocate_buttons (const WDialog
* h
, gboolean all_buttons
)
1497 find_calc_button_locations (h
, all_buttons
);
1499 for (i
= 0; i
< fbuts_num
; i
++)
1500 fbuts
[i
].button
->x
= CONST_WIDGET (h
)->x
+ fbuts
[i
].x
;
1503 /* --------------------------------------------------------------------------------------------- */
1506 find_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1508 WDialog
*h
= DIALOG (w
);
1513 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1515 gboolean unparsed_view
= (parm
== KEY_F (13));
1517 return view_edit_currently_selected_file (unparsed_view
, FALSE
);
1519 if (parm
== KEY_F (4))
1520 return view_edit_currently_selected_file (FALSE
, TRUE
);
1521 return MSG_NOT_HANDLED
;
1524 dlg_set_size (h
, LINES
- 4, COLS
- 16);
1525 find_relocate_buttons (h
, TRUE
);
1533 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
1537 /* --------------------------------------------------------------------------------------------- */
1538 /** Handles the Stop/Start button in the find window */
1541 start_stop (WButton
* button
, int action
)
1543 Widget
*w
= WIDGET (button
);
1548 widget_idle (WIDGET (find_dlg
), running
);
1549 is_start
= !is_start
;
1551 status_update (is_start
? _("Stopped") : _("Searching"));
1552 button_set_text (button
, fbuts
[is_start
? 3 : 2].text
);
1554 find_relocate_buttons (w
->owner
, FALSE
);
1555 dlg_redraw (w
->owner
);
1560 /* --------------------------------------------------------------------------------------------- */
1561 /** Handle view command, when invoked as a button */
1564 find_do_view_file (WButton
* button
, int action
)
1569 view_edit_currently_selected_file (FALSE
, FALSE
);
1573 /* --------------------------------------------------------------------------------------------- */
1574 /** Handle edit command, when invoked as a button */
1577 find_do_edit_file (WButton
* button
, int action
)
1582 view_edit_currently_selected_file (FALSE
, TRUE
);
1586 /* --------------------------------------------------------------------------------------------- */
1595 static gboolean i18n_flag
= FALSE
;
1599 for (i
= 0; i
< fbuts_num
; i
++)
1602 fbuts
[i
].text
= _(fbuts
[i
].text
);
1603 #endif /* ENABLE_NLS */
1604 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1605 if (fbuts
[i
].flags
== DEFPUSH_BUTTON
)
1616 dlg_create (TRUE
, 0, 0, lines
, cols
, dialog_colors
, find_callback
, NULL
, "[Find File]",
1617 _("Find File"), DLG_CENTER
);
1619 find_calc_button_locations (find_dlg
, TRUE
);
1622 find_list
= listbox_new (y
, 2, lines
- 10, cols
- 4, FALSE
, NULL
);
1623 add_widget_autopos (find_dlg
, find_list
, WPOS_KEEP_ALL
, NULL
);
1624 y
+= WIDGET (find_list
)->lines
;
1626 add_widget_autopos (find_dlg
, hline_new (y
++, -1, -1), WPOS_KEEP_BOTTOM
, NULL
);
1628 found_num_label
= label_new (y
++, 4, "");
1629 add_widget_autopos (find_dlg
, found_num_label
, WPOS_KEEP_BOTTOM
, NULL
);
1631 status_label
= label_new (y
++, 4, _("Searching"));
1632 add_widget_autopos (find_dlg
, status_label
, WPOS_KEEP_BOTTOM
, NULL
);
1634 add_widget_autopos (find_dlg
, hline_new (y
++, -1, -1), WPOS_KEEP_BOTTOM
, NULL
);
1636 for (i
= 0; i
< fbuts_num
; i
++)
1639 fbuts
[3].button
= fbuts
[2].button
;
1644 (y
, fbuts
[i
].x
, fbuts
[i
].ret_cmd
, fbuts
[i
].flags
, fbuts
[i
].text
,
1645 fbuts
[i
].callback
));
1646 add_widget_autopos (find_dlg
, fbuts
[i
].button
, WPOS_KEEP_BOTTOM
, NULL
);
1649 if (i
== quit_button
)
1653 dlg_select_widget (find_list
);
1656 /* --------------------------------------------------------------------------------------------- */
1663 search_content_handle
= mc_search_new (content_pattern
, NULL
);
1664 if (search_content_handle
)
1666 search_content_handle
->search_type
=
1667 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1668 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1669 search_content_handle
->whole_words
= options
.content_whole_words
;
1671 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1674 search_file_handle
= mc_search_new (find_pattern
, NULL
);
1675 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1676 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1678 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1680 search_file_handle
->is_entire_line
= options
.file_pattern
;
1684 widget_idle (WIDGET (find_dlg
), TRUE
);
1685 ret
= dlg_run (find_dlg
);
1687 mc_search_free (search_file_handle
);
1688 search_file_handle
= NULL
;
1689 mc_search_free (search_content_handle
);
1690 search_content_handle
= NULL
;
1695 /* --------------------------------------------------------------------------------------------- */
1700 widget_idle (WIDGET (find_dlg
), FALSE
);
1701 dlg_destroy (find_dlg
);
1704 /* --------------------------------------------------------------------------------------------- */
1707 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1708 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1710 int return_value
= 0;
1711 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1715 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1716 find_pattern
= (char *) pattern
;
1718 content_pattern
= NULL
;
1719 if (content
!= NULL
&& str_is_valid_string (content
))
1720 content_pattern
= g_strdup (content
);
1723 parse_ignore_dirs (ignore_dirs
);
1724 push_directory (vfs_path_from_str (start_dir
));
1726 return_value
= run_process ();
1728 /* Clear variables */
1731 get_list_info (&file_tmp
, &dir_tmp
, NULL
, NULL
);
1734 *dirname
= g_strdup (dir_tmp
);
1736 *filename
= g_strdup (file_tmp
);
1738 if (return_value
== B_PANELIZE
&& *filename
)
1740 int link_to_dir
, stale_link
;
1744 dir_list
*list
= ¤t_panel
->dir
;
1747 dir_list_init (list
);
1749 for (i
= 0, entry
= listbox_get_first_link (find_list
); entry
!= NULL
;
1750 i
++, entry
= g_list_next (entry
))
1752 const char *lc_filename
= NULL
;
1753 WLEntry
*le
= LENTRY (entry
->data
);
1754 find_match_location_t
*location
= le
->data
;
1757 if ((le
->text
== NULL
) || (location
== NULL
) || (location
->dir
== NULL
))
1760 if (content_pattern
!= NULL
)
1761 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1763 lc_filename
= le
->text
+ 4;
1765 name
= mc_build_filename (location
->dir
, lc_filename
, (char *) NULL
);
1766 /* skip initial start dir */
1767 if (start_dir_len
< 0)
1771 p
= name
+ (size_t) start_dir_len
;
1772 if (IS_PATH_SEP (*p
))
1776 if (!handle_path (p
, &st
, &link_to_dir
, &stale_link
))
1781 /* Need to grow the *list? */
1782 if (list
->len
== list
->size
&& !dir_list_grow (list
, DIR_LIST_RESIZE_STEP
))
1788 /* don't add files more than once to the panel */
1789 if (content_pattern
!= NULL
&& list
->len
!= 0
1790 && strcmp (list
->list
[list
->len
- 1].fname
, p
) == 0)
1796 if (list
->len
== 0) /* first turn i.e clean old list */
1797 panel_clean_dir (current_panel
);
1798 list
->list
[list
->len
].fnamelen
= strlen (p
);
1799 list
->list
[list
->len
].fname
= g_strndup (p
, list
->list
[list
->len
].fnamelen
);
1800 list
->list
[list
->len
].f
.marked
= 0;
1801 list
->list
[list
->len
].f
.link_to_dir
= link_to_dir
;
1802 list
->list
[list
->len
].f
.stale_link
= stale_link
;
1803 list
->list
[list
->len
].f
.dir_size_computed
= 0;
1804 list
->list
[list
->len
].st
= st
;
1805 list
->list
[list
->len
].sort_key
= NULL
;
1806 list
->list
[list
->len
].second_sort_key
= NULL
;
1809 if ((list
->len
& 15) == 0)
1815 current_panel
->is_panelized
= TRUE
;
1818 if (start_dir_len
< 0)
1821 vfs_path_free (current_panel
->cwd_vpath
);
1822 current_panel
->cwd_vpath
= vfs_path_from_str (PATH_SEP_STR
);
1823 ret
= chdir (PATH_SEP_STR
);
1826 panelize_save_panel (current_panel
);
1830 g_free (content_pattern
);
1832 do_search (NULL
); /* force do_search to release resources */
1833 MC_PTR_FREE (old_dir
);
1834 rotate_dash (FALSE
);
1836 return return_value
;
1839 /* --------------------------------------------------------------------------------------------- */
1840 /*** public functions ****************************************************************************/
1841 /* --------------------------------------------------------------------------------------------- */
1846 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1847 ssize_t start_dir_len
;
1849 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1851 char *filename
= NULL
, *dirname
= NULL
;
1854 if (pattern
[0] != '\0')
1856 last_refresh
.tv_sec
= 0;
1857 last_refresh
.tv_usec
= 0;
1860 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
,
1865 g_free (ignore_dirs
);
1870 if (dirname
!= NULL
)
1872 vfs_path_t
*dirname_vpath
;
1874 dirname_vpath
= vfs_path_from_str (dirname
);
1875 do_cd (dirname_vpath
, cd_exact
);
1876 vfs_path_free (dirname_vpath
);
1877 if (filename
!= NULL
)
1878 try_to_select (current_panel
,
1879 filename
+ (content
!= NULL
1880 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1882 else if (filename
!= NULL
)
1884 vfs_path_t
*filename_vpath
;
1886 filename_vpath
= vfs_path_from_str (filename
);
1887 do_cd (filename_vpath
, cd_exact
);
1888 vfs_path_free (filename_vpath
);
1896 if (v
== B_ENTER
|| v
== B_CANCEL
)
1899 if (v
== B_PANELIZE
)
1901 panel_re_sort (current_panel
);
1902 try_to_select (current_panel
, NULL
);
1908 /* --------------------------------------------------------------------------------------------- */