2 Find file command for the Midnight Commander
4 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
6 The Free Software Foundation, Inc.
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * \brief Source: Find file command
40 #include "lib/global.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/key.h"
45 #include "lib/search.h"
46 #include "lib/mcconfig.h"
47 #include "lib/vfs/vfs.h"
48 #include "lib/strutil.h"
49 #include "lib/widget.h"
50 #include "lib/util.h" /* canonicalize_pathname() */
52 #include "src/setup.h" /* verbose */
53 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
54 #include "src/main.h" /* do_cd */
57 #include "cmd.h" /* view_file_at_line */
58 #include "midnight.h" /* current_panel */
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 /* Size of the find window */
69 #define FIND2_Y (LINES - 4)
71 #define FIND2_X_USE (FIND2_X - 20)
73 /*** file scope type declarations ****************************************************************/
75 /* A couple of extra messages we need */
92 /* find file options */
95 /* file name options */
96 gboolean file_case_sens
;
97 gboolean file_pattern
;
100 gboolean file_all_charsets
;
102 /* file content options */
103 gboolean content_use
;
104 gboolean content_case_sens
;
105 gboolean content_regexp
;
106 gboolean content_first_hit
;
107 gboolean content_whole_words
;
108 gboolean content_all_charsets
;
110 /* whether use ignore dirs or not */
111 gboolean ignore_dirs_enable
;
112 /* list of directories to be ignored, separated by ':' */
114 } find_file_options_t
;
116 /*** file scope variables ************************************************************************/
118 /* Parsed ignore dirs */
119 static char **find_ignore_dirs
= NULL
;
121 /* Size of the find parameters window */
123 static int FIND_Y
= 19;
125 static int FIND_Y
= 18;
127 static int FIND_X
= 68;
129 static int FIND2_X
= 64;
131 /* static variables to remember find parameters */
132 static WInput
*in_start
; /* Start path */
133 static WInput
*in_name
; /* Filename */
134 static WInput
*in_with
; /* Text */
135 static WInput
*in_ignore
;
136 static WLabel
*content_label
; /* 'Content:' label */
137 static WCheck
*file_case_sens_cbox
; /* "case sensitive" checkbox */
138 static WCheck
*file_pattern_cbox
; /* File name is glob or regexp */
139 static WCheck
*recursively_cbox
;
140 static WCheck
*skip_hidden_cbox
;
141 static WCheck
*content_use_cbox
; /* Take into account the Content field */
142 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
143 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
144 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
145 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
147 static WCheck
*file_all_charsets_cbox
;
148 static WCheck
*content_all_charsets_cbox
;
150 static WCheck
*ignore_dirs_cbox
;
152 static gboolean running
= FALSE
; /* nice flag */
153 static char *find_pattern
= NULL
; /* Pattern to search */
154 static char *content_pattern
= NULL
; /* pattern to search inside files; if
155 content_regexp_flag is true, it contains the
156 regex pattern, else the search string. */
157 static unsigned long matches
; /* Number of matches */
158 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
159 static char *old_dir
= NULL
;
161 /* Where did we stop */
163 static int last_line
;
166 static size_t ignore_count
= 0;
168 static Dlg_head
*find_dlg
; /* The dialog */
169 static WButton
*stop_button
; /* pointer to the stop button */
170 static WLabel
*status_label
; /* Finished, Searching etc. */
171 static WLabel
*found_num_label
; /* Number of found items */
172 static WListbox
*find_list
; /* Listbox with the file list */
174 /* This keeps track of the directory stack */
175 #if GLIB_CHECK_VERSION (2, 14, 0)
176 static GQueue dir_queue
= G_QUEUE_INIT
;
178 typedef struct dir_stack
181 struct dir_stack
*prev
;
184 static dir_stack
*dir_stack_base
= 0;
185 #endif /* GLIB_CHECK_VERSION */
191 int len
; /* length including space and brackets */
195 {N_("&Suspend"), 11, 29},
196 {N_("Con&tinue"), 12, 29},
197 {N_("&Chdir"), 11, 3},
198 {N_("&Again"), 9, 17},
199 {N_("&Quit"), 8, 43},
200 {N_("Pane&lize"), 12, 3},
201 {N_("&View - F3"), 13, 20},
202 {N_("&Edit - F4"), 13, 38}
206 static find_file_options_t options
= {
207 TRUE
, TRUE
, TRUE
, FALSE
, FALSE
,
208 FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
211 static char *in_start_dir
= INPUT_LAST_TEXT
;
213 static mc_search_t
*search_file_handle
= NULL
;
214 static mc_search_t
*search_content_handle
= NULL
;
216 /*** file scope functions ************************************************************************/
219 parse_ignore_dirs (const char *ignore_dirs
)
221 size_t r
= 0, w
= 0; /* read and write iterators */
223 if (!options
.ignore_dirs_enable
|| ignore_dirs
== NULL
|| ignore_dirs
[0] == '\0')
226 find_ignore_dirs
= g_strsplit (ignore_dirs
, ":", -1);
228 /* Values like '/foo::/bar: produce holes in list.
229 * Find and remove them */
230 for (; find_ignore_dirs
[r
] != NULL
; r
++)
232 if (find_ignore_dirs
[r
][0] == '\0')
234 /* empty entry -- skip it */
235 g_free (find_ignore_dirs
[r
]);
236 find_ignore_dirs
[r
] = NULL
;
242 /* copy entry to the previous free array cell */
243 find_ignore_dirs
[w
] = find_ignore_dirs
[r
];
244 find_ignore_dirs
[r
] = NULL
;
247 canonicalize_pathname (find_ignore_dirs
[w
]);
248 if (find_ignore_dirs
[w
][0] != '\0')
252 g_free (find_ignore_dirs
[w
]);
253 find_ignore_dirs
[w
] = NULL
;
257 if (find_ignore_dirs
[0] == NULL
)
259 g_strfreev (find_ignore_dirs
);
260 find_ignore_dirs
= NULL
;
264 /* --------------------------------------------------------------------------------------------- */
267 find_load_options (void)
269 static gboolean loaded
= FALSE
;
277 options
.file_case_sens
=
278 mc_config_get_bool (mc_main_config
, "FindFile", "file_case_sens", TRUE
);
279 options
.file_pattern
=
280 mc_config_get_bool (mc_main_config
, "FindFile", "file_shell_pattern", TRUE
);
281 options
.find_recurs
= mc_config_get_bool (mc_main_config
, "FindFile", "file_find_recurs", TRUE
);
282 options
.skip_hidden
=
283 mc_config_get_bool (mc_main_config
, "FindFile", "file_skip_hidden", FALSE
);
284 options
.file_all_charsets
=
285 mc_config_get_bool (mc_main_config
, "FindFile", "file_all_charsets", FALSE
);
286 options
.content_use
= mc_config_get_bool (mc_main_config
, "FindFile", "content_use", TRUE
);
287 options
.content_case_sens
=
288 mc_config_get_bool (mc_main_config
, "FindFile", "content_case_sens", TRUE
);
289 options
.content_regexp
=
290 mc_config_get_bool (mc_main_config
, "FindFile", "content_regexp", FALSE
);
291 options
.content_first_hit
=
292 mc_config_get_bool (mc_main_config
, "FindFile", "content_first_hit", FALSE
);
293 options
.content_whole_words
=
294 mc_config_get_bool (mc_main_config
, "FindFile", "content_whole_words", FALSE
);
295 options
.content_all_charsets
=
296 mc_config_get_bool (mc_main_config
, "FindFile", "content_all_charsets", FALSE
);
297 options
.ignore_dirs_enable
=
298 mc_config_get_bool (mc_main_config
, "FindFile", "ignore_dirs_enable", TRUE
);
300 /* Back compatibility: try load old parameter at first */
301 ignore_dirs
= mc_config_get_string (mc_main_config
, "Misc", "find_ignore_dirs", "");
302 mc_config_del_key (mc_main_config
, "Misc", "find_ignore_dirs");
304 /* Then load new parameters */
305 options
.ignore_dirs
= mc_config_get_string (mc_main_config
, "FindFile", "ignore_dirs", "");
306 if (options
.ignore_dirs
[0] != '\0')
307 g_free (ignore_dirs
);
310 g_free (options
.ignore_dirs
);
311 options
.ignore_dirs
= ignore_dirs
;
314 if (options
.ignore_dirs
[0] == '\0')
316 g_free (options
.ignore_dirs
);
317 options
.ignore_dirs
= NULL
;
321 /* --------------------------------------------------------------------------------------------- */
324 find_save_options (void)
326 mc_config_set_bool (mc_main_config
, "FindFile", "file_case_sens", options
.file_case_sens
);
327 mc_config_set_bool (mc_main_config
, "FindFile", "file_shell_pattern", options
.file_pattern
);
328 mc_config_set_bool (mc_main_config
, "FindFile", "file_find_recurs", options
.find_recurs
);
329 mc_config_set_bool (mc_main_config
, "FindFile", "file_skip_hidden", options
.skip_hidden
);
330 mc_config_set_bool (mc_main_config
, "FindFile", "file_all_charsets", options
.file_all_charsets
);
331 mc_config_set_bool (mc_main_config
, "FindFile", "content_use", options
.content_use
);
332 mc_config_set_bool (mc_main_config
, "FindFile", "content_case_sens", options
.content_case_sens
);
333 mc_config_set_bool (mc_main_config
, "FindFile", "content_regexp", options
.content_regexp
);
334 mc_config_set_bool (mc_main_config
, "FindFile", "content_first_hit", options
.content_first_hit
);
335 mc_config_set_bool (mc_main_config
, "FindFile", "content_whole_words",
336 options
.content_whole_words
);
337 mc_config_set_bool (mc_main_config
, "FindFile", "content_all_charsets",
338 options
.content_all_charsets
);
339 mc_config_set_bool (mc_main_config
, "FindFile", "ignore_dirs_enable",
340 options
.ignore_dirs_enable
);
341 mc_config_set_string (mc_main_config
, "FindFile", "ignore_dirs", options
.ignore_dirs
);
344 /* --------------------------------------------------------------------------------------------- */
347 add_to_list (const char *text
, void *data
)
349 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
);
352 /* --------------------------------------------------------------------------------------------- */
355 stop_idle (void *data
)
357 set_idle_proc (data
, 0);
360 /* --------------------------------------------------------------------------------------------- */
363 status_update (const char *text
)
365 label_set_text (status_label
, text
);
368 /* --------------------------------------------------------------------------------------------- */
371 found_num_update (void)
373 char buffer
[BUF_TINY
];
374 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
375 label_set_text (found_num_label
, buffer
);
378 /* --------------------------------------------------------------------------------------------- */
381 get_list_info (char **file
, char **dir
)
383 listbox_get_current (find_list
, file
, (void **) dir
);
386 /* --------------------------------------------------------------------------------------------- */
387 /** check regular expression */
390 find_check_regexp (const char *r
)
393 gboolean regexp_ok
= FALSE
;
395 search
= mc_search_new (r
, -1);
399 search
->search_type
= MC_SEARCH_T_REGEX
;
400 regexp_ok
= mc_search_prepare (search
);
401 mc_search_free (search
);
407 /* --------------------------------------------------------------------------------------------- */
409 * Callback for the parameter dialog.
410 * Validate regex, prevent closing the dialog if it's invalid.
414 find_parm_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
419 if (sender
== (Widget
*) content_use_cbox
)
421 gboolean disable
= !(content_use_cbox
->state
& C_BOOL
);
423 widget_disable (content_label
->widget
, disable
);
424 send_message ((Widget
*) content_label
, WIDGET_DRAW
, 0);
425 widget_disable (in_with
->widget
, disable
);
426 send_message ((Widget
*) in_with
, WIDGET_DRAW
, 0);
427 widget_disable (content_first_hit_cbox
->widget
, disable
);
428 send_message ((Widget
*) content_first_hit_cbox
, WIDGET_DRAW
, 0);
429 widget_disable (content_regexp_cbox
->widget
, disable
);
430 send_message ((Widget
*) content_regexp_cbox
, WIDGET_DRAW
, 0);
431 widget_disable (content_case_sens_cbox
->widget
, disable
);
432 send_message ((Widget
*) content_case_sens_cbox
, WIDGET_DRAW
, 0);
434 widget_disable (content_all_charsets_cbox
->widget
, disable
);
435 send_message ((Widget
*) content_all_charsets_cbox
, WIDGET_DRAW
, 0);
437 widget_disable (content_whole_words_cbox
->widget
, disable
);
438 send_message ((Widget
*) content_whole_words_cbox
, WIDGET_DRAW
, 0);
443 if (sender
== (Widget
*) ignore_dirs_cbox
)
445 gboolean disable
= !(ignore_dirs_cbox
->state
& C_BOOL
);
447 widget_disable (in_ignore
->widget
, disable
);
448 send_message ((Widget
*) in_ignore
, WIDGET_DRAW
, 0);
453 return MSG_NOT_HANDLED
;
457 if (h
->ret_value
!= B_ENTER
)
460 /* check filename regexp */
461 if (!(file_pattern_cbox
->state
& C_BOOL
)
462 && (in_name
->buffer
[0] != '\0') && !find_check_regexp (in_name
->buffer
))
464 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
465 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
466 dlg_select_widget (in_name
);
470 /* check content regexp */
471 if ((content_use_cbox
->state
& C_BOOL
) && (content_regexp_cbox
->state
& C_BOOL
)
472 && (in_with
->buffer
[0] != '\0') && !find_check_regexp (in_with
->buffer
))
474 h
->state
= DLG_ACTIVE
; /* Don't stop the dialog */
475 message (D_ERROR
, MSG_ERROR
, _("Malformed regular expression"));
476 dlg_select_widget (in_with
);
483 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
487 /* --------------------------------------------------------------------------------------------- */
489 * find_parameters: gets information from the user
491 * If the return value is TRUE, then the following holds:
493 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
494 * They are newly allocated strings and must be freed when uneeded.
496 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
497 * of start_dir (which is absolute). It is used to get a relative pats of find results.
501 find_parameters (char **start_dir
, ssize_t
* start_dir_len
,
502 char **ignore_dirs
, char **pattern
, char **content
)
504 gboolean return_value
;
507 const char *file_case_label
= N_("Cas&e sensitive");
508 const char *file_pattern_label
= N_("&Using shell patterns");
509 const char *file_recurs_label
= N_("&Find recursively");
510 const char *file_skip_hidden_label
= N_("S&kip hidden");
512 const char *file_all_charsets_label
= N_("&All charsets");
516 const char *content_use_label
= N_("Sea&rch for content");
517 const char *content_case_label
= N_("Case sens&itive");
518 const char *content_regexp_label
= N_("Re&gular expression");
519 const char *content_first_hit_label
= N_("Fir&st hit");
520 const char *content_whole_words_label
= N_("&Whole words");
522 const char *content_all_charsets_label
= N_("A&ll charsets");
525 const char *buts
[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
534 int i
= sizeof (buts
) / sizeof (buts
[0]);
536 buts
[i
] = _(buts
[i
]);
538 file_case_label
= _(file_case_label
);
539 file_pattern_label
= _(file_pattern_label
);
540 file_recurs_label
= _(file_recurs_label
);
541 file_skip_hidden_label
= _(file_skip_hidden_label
);
543 file_all_charsets_label
= _(file_all_charsets_label
);
544 content_all_charsets_label
= _(content_all_charsets_label
);
546 content_use_label
= _(content_use_label
);
547 content_case_label
= _(content_case_label
);
548 content_regexp_label
= _(content_regexp_label
);
549 content_first_hit_label
= _(content_first_hit_label
);
550 content_whole_words_label
= _(content_whole_words_label
);
552 #endif /* ENABLE_NLS */
554 b0
= str_term_width1 (buts
[0]) + 6; /* default button */
555 b1
= str_term_width1 (buts
[1]) + 4;
556 b2
= str_term_width1 (buts
[2]) + 4;
558 find_load_options ();
560 if (in_start_dir
== NULL
)
561 in_start_dir
= g_strdup (".");
563 disable
= !options
.content_use
;
566 create_dlg (TRUE
, 0, 0, FIND_Y
, FIND_X
, dialog_colors
,
567 find_parm_callback
, "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
569 add_widget (find_dlg
,
570 button_new (FIND_Y
- 3, FIND_X
* 3 / 4 - b1
/ 2, B_CANCEL
, NORMAL_BUTTON
, buts
[1],
572 add_widget (find_dlg
,
573 button_new (FIND_Y
- 3, FIND_X
/ 4 - b0
/ 2, B_ENTER
, DEFPUSH_BUTTON
, buts
[0], 0));
575 cbox_position
= FIND_Y
- 5;
577 content_first_hit_cbox
=
578 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_first_hit
,
579 content_first_hit_label
);
580 widget_disable (content_first_hit_cbox
->widget
, disable
);
581 add_widget (find_dlg
, content_first_hit_cbox
);
583 content_whole_words_cbox
=
584 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_whole_words
,
585 content_whole_words_label
);
586 widget_disable (content_whole_words_cbox
->widget
, disable
);
587 add_widget (find_dlg
, content_whole_words_cbox
);
590 content_all_charsets_cbox
= check_new (cbox_position
--, FIND_X
/ 2 + 1,
591 options
.content_all_charsets
,
592 content_all_charsets_label
);
593 widget_disable (content_all_charsets_cbox
->widget
, disable
);
594 add_widget (find_dlg
, content_all_charsets_cbox
);
597 content_case_sens_cbox
=
598 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_case_sens
, content_case_label
);
599 widget_disable (content_case_sens_cbox
->widget
, disable
);
600 add_widget (find_dlg
, content_case_sens_cbox
);
602 content_regexp_cbox
=
603 check_new (cbox_position
--, FIND_X
/ 2 + 1, options
.content_regexp
, content_regexp_label
);
604 widget_disable (content_regexp_cbox
->widget
, disable
);
605 add_widget (find_dlg
, content_regexp_cbox
);
607 cbox_position
= FIND_Y
- 6;
609 skip_hidden_cbox
= check_new (cbox_position
--, 3, options
.skip_hidden
, file_skip_hidden_label
);
610 add_widget (find_dlg
, skip_hidden_cbox
);
613 file_all_charsets_cbox
=
614 check_new (cbox_position
--, 3, options
.file_all_charsets
, file_all_charsets_label
);
615 add_widget (find_dlg
, file_all_charsets_cbox
);
618 file_case_sens_cbox
= check_new (cbox_position
--, 3, options
.file_case_sens
, file_case_label
);
619 add_widget (find_dlg
, file_case_sens_cbox
);
621 file_pattern_cbox
= check_new (cbox_position
--, 3, options
.file_pattern
, file_pattern_label
);
622 add_widget (find_dlg
, file_pattern_cbox
);
624 recursively_cbox
= check_new (cbox_position
, 3, options
.find_recurs
, file_recurs_label
);
625 add_widget (find_dlg
, recursively_cbox
);
627 /* This checkbox is located in the second column */
629 check_new (cbox_position
, FIND_X
/ 2 + 1, options
.content_use
, content_use_label
);
630 add_widget (find_dlg
, content_use_cbox
);
633 input_new (8, FIND_X
/ 2 + 1, input_get_default_colors (), FIND_X
/ 2 - 4, INPUT_LAST_TEXT
,
634 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_DEFAULT
);
635 widget_disable (in_with
->widget
, disable
);
636 add_widget (find_dlg
, in_with
);
638 content_label
= label_new (7, FIND_X
/ 2 + 1, _("Content:"));
639 widget_disable (content_label
->widget
, disable
);
640 add_widget (find_dlg
, content_label
);
642 in_name
= input_new (8, 3, input_get_default_colors (),
643 FIND_X
/ 2 - 4, INPUT_LAST_TEXT
, "name", INPUT_COMPLETE_DEFAULT
);
644 add_widget (find_dlg
, in_name
);
645 add_widget (find_dlg
, label_new (7, 3, _("File name:")));
647 in_ignore
= input_new (5, 3, input_get_default_colors (), FIND_X
- 6,
648 options
.ignore_dirs
!= NULL
? options
.ignore_dirs
: "",
649 "ignoredirs", INPUT_COMPLETE_DEFAULT
);
650 widget_disable (in_ignore
->widget
, !options
.ignore_dirs_enable
);
651 add_widget (find_dlg
, in_ignore
);
654 check_new (4, 3, options
.ignore_dirs_enable
, _("Ena&ble ignore directories:"));
655 add_widget (find_dlg
, ignore_dirs_cbox
);
657 add_widget (find_dlg
, button_new (3, FIND_X
- b2
- 2, B_TREE
, NORMAL_BUTTON
, buts
[2], 0));
659 in_start
= input_new (3, 3, input_get_default_colors (),
660 FIND_X
- b2
- 6, in_start_dir
, "start", INPUT_COMPLETE_DEFAULT
);
661 add_widget (find_dlg
, in_start
);
662 add_widget (find_dlg
, label_new (2, 3, _("Start at:")));
665 dlg_select_widget (in_name
);
667 switch (run_dlg (find_dlg
))
670 return_value
= FALSE
;
677 temp_dir
= in_start
->buffer
;
678 if ((temp_dir
[0] == '\0') || ((temp_dir
[0] == '.') && (temp_dir
[1] == '\0')))
679 temp_dir
= vfs_path_to_str (current_panel
->cwd_vpath
);
681 temp_dir
= g_strdup (temp_dir
);
683 if (in_start_dir
!= INPUT_LAST_TEXT
)
684 g_free (in_start_dir
);
685 in_start_dir
= tree_box (temp_dir
);
686 if (in_start_dir
== NULL
)
687 in_start_dir
= temp_dir
;
691 input_assign_text (in_start
, in_start_dir
);
693 /* Warning: Dreadful goto */
702 options
.file_all_charsets
= file_all_charsets_cbox
->state
& C_BOOL
;
703 options
.content_all_charsets
= content_all_charsets_cbox
->state
& C_BOOL
;
705 options
.content_use
= content_use_cbox
->state
& C_BOOL
;
706 options
.content_case_sens
= content_case_sens_cbox
->state
& C_BOOL
;
707 options
.content_regexp
= content_regexp_cbox
->state
& C_BOOL
;
708 options
.content_first_hit
= content_first_hit_cbox
->state
& C_BOOL
;
709 options
.content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
710 options
.find_recurs
= recursively_cbox
->state
& C_BOOL
;
711 options
.file_pattern
= file_pattern_cbox
->state
& C_BOOL
;
712 options
.file_case_sens
= file_case_sens_cbox
->state
& C_BOOL
;
713 options
.skip_hidden
= skip_hidden_cbox
->state
& C_BOOL
;
714 options
.ignore_dirs_enable
= ignore_dirs_cbox
->state
& C_BOOL
;
715 g_free (options
.ignore_dirs
);
716 options
.ignore_dirs
= g_strdup (in_ignore
->buffer
);
718 *content
= (options
.content_use
&& in_with
->buffer
[0] != '\0')
719 ? g_strdup (in_with
->buffer
) : NULL
;
720 *start_dir
= in_start
->buffer
[0] != '\0' ? in_start
->buffer
: (char *) ".";
721 *pattern
= g_strdup (in_name
->buffer
);
722 if (in_start_dir
!= INPUT_LAST_TEXT
)
723 g_free (in_start_dir
);
724 in_start_dir
= g_strdup (*start_dir
);
726 s
= tilde_expand (*start_dir
);
727 canonicalize_pathname (s
);
729 if (s
[0] == '.' && s
[1] == '\0')
731 *start_dir
= vfs_path_to_str (current_panel
->cwd_vpath
);
732 /* FIXME: is current_panel->cwd_vpath canonicalized? */
733 /* relative paths will be used in panelization */
734 *start_dir_len
= (ssize_t
) strlen (*start_dir
);
737 else if (g_path_is_absolute (s
))
744 /* relative paths will be used in panelization */
747 cwd_str
= vfs_path_to_str (current_panel
->cwd_vpath
);
748 *start_dir
= mc_build_filename (cwd_str
, s
, (char *) NULL
);
749 *start_dir_len
= (ssize_t
) strlen (cwd_str
);
754 if (!options
.ignore_dirs_enable
|| in_ignore
->buffer
[0] == '\0'
755 || (in_ignore
->buffer
[0] == '.' && in_ignore
->buffer
[1] == '\0'))
758 *ignore_dirs
= g_strdup (in_ignore
->buffer
);
760 find_save_options ();
766 destroy_dlg (find_dlg
);
771 /* --------------------------------------------------------------------------------------------- */
773 #if GLIB_CHECK_VERSION (2, 14, 0)
775 push_directory (const vfs_path_t
* dir
)
777 g_queue_push_head (&dir_queue
, (void *) dir
);
780 /* --------------------------------------------------------------------------------------------- */
782 static inline vfs_path_t
*
785 return (vfs_path_t
*) g_queue_pop_tail (&dir_queue
);
788 /* --------------------------------------------------------------------------------------------- */
789 /** Remove all the items from the stack */
794 g_queue_foreach (&dir_queue
, (GFunc
) vfs_path_free
, NULL
);
795 g_queue_clear (&dir_queue
);
798 /* --------------------------------------------------------------------------------------------- */
800 #else /* GLIB_CHECK_VERSION */
802 push_directory (const vfs_path_t
* dir
)
806 new = g_new (dir_stack
, 1);
807 new->name
= (vfs_path_t
*) dir
;
808 new->prev
= dir_stack_base
;
809 dir_stack_base
= new;
812 /* --------------------------------------------------------------------------------------------- */
817 vfs_path_t
*name
= NULL
;
819 if (dir_stack_base
!= NULL
)
822 name
= dir_stack_base
->name
;
823 next
= dir_stack_base
->prev
;
824 g_free (dir_stack_base
);
825 dir_stack_base
= next
;
831 /* --------------------------------------------------------------------------------------------- */
832 /** Remove all the items from the stack */
837 vfs_path_t
*dir
= NULL
;
839 while ((dir
= pop_directory ()) != NULL
)
842 #endif /* GLIB_CHECK_VERSION */
844 /* --------------------------------------------------------------------------------------------- */
847 insert_file (const char *dir
, const char *file
)
849 char *tmp_name
= NULL
;
850 static char *dirname
= NULL
;
852 while (dir
[0] == PATH_SEP
&& dir
[1] == PATH_SEP
)
857 if (strcmp (old_dir
, dir
))
860 old_dir
= g_strdup (dir
);
861 dirname
= add_to_list (dir
, NULL
);
866 old_dir
= g_strdup (dir
);
867 dirname
= add_to_list (dir
, NULL
);
870 tmp_name
= g_strdup_printf (" %s", file
);
871 add_to_list (tmp_name
, dirname
);
875 /* --------------------------------------------------------------------------------------------- */
878 find_add_match (const char *dir
, const char *file
)
880 insert_file (dir
, file
);
884 listbox_select_first (find_list
);
885 send_message (&find_list
->widget
, WIDGET_DRAW
, 0);
891 /* --------------------------------------------------------------------------------------------- */
895 * Returns malloced null-terminated line from file file_fd.
896 * Input is buffered in buf_size long buffer.
897 * Current pos in buf is stored in pos.
898 * n_read - number of read chars.
899 * has_newline - is there newline ?
903 get_line_at (int file_fd
, char *buf
, int buf_size
, int *pos
, int *n_read
, gboolean
* has_newline
)
915 *n_read
= mc_read (file_fd
, buf
, buf_size
);
923 /* skip possible leading zero(s) */
929 if (i
>= buffer_size
- 1)
930 buffer
= g_realloc (buffer
, buffer_size
+= 80);
939 *has_newline
= (ch
!= '\0');
947 /* --------------------------------------------------------------------------------------------- */
949 static FindProgressStatus
950 check_find_events (Dlg_head
* h
)
956 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
959 dlg_process_event (h
, c
, &event
);
960 if (h
->ret_value
== B_ENTER
961 || h
->ret_value
== B_CANCEL
|| h
->ret_value
== B_AGAIN
|| h
->ret_value
== B_PANELIZE
)
963 /* dialog terminated */
966 if (!(h
->flags
& DLG_WANT_IDLE
))
968 /* searching suspended */
976 /* --------------------------------------------------------------------------------------------- */
980 * Search the content_pattern string in the DIRECTORY/FILE.
981 * It will add the found entries to the find listbox.
983 * returns FALSE if do_search should look for another file
984 * TRUE if do_search should exit and proceed to the event handler
988 search_content (Dlg_head
* h
, const char *directory
, const char *filename
)
993 gboolean ret_val
= FALSE
;
996 vpath
= vfs_path_build_filename (directory
, filename
, (char *) NULL
);
998 if (mc_stat (vpath
, &s
) != 0 || !S_ISREG (s
.st_mode
))
1000 vfs_path_free (vpath
);
1004 file_fd
= mc_open (vpath
, O_RDONLY
);
1005 vfs_path_free (vpath
);
1010 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), str_trunc (filename
, FIND2_X_USE
));
1012 status_update (buffer
);
1015 tty_enable_interrupt_key ();
1016 tty_got_interrupt ();
1022 gboolean has_newline
;
1024 gboolean found
= FALSE
;
1026 char result
[BUF_MEDIUM
];
1030 /* We've been previously suspended, start from the previous position */
1036 && (p
= get_line_at (file_fd
, buffer
, sizeof (buffer
),
1037 &pos
, &n_read
, &has_newline
)) != NULL
)
1039 if (!found
/* Search in binary line once */
1040 && mc_search_run (search_content_handle
,
1041 (const void *) p
, 0, strlen (p
), &found_len
))
1043 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
1044 find_add_match (directory
, result
);
1049 if (found
&& options
.content_first_hit
)
1058 if ((line
& 0xff) == 0)
1060 FindProgressStatus res
;
1061 res
= check_find_events (h
);
1080 tty_disable_interrupt_key ();
1085 /* --------------------------------------------------------------------------------------------- */
1088 If dir is absolute, this means we're within dir and searching file here.
1089 If dir is relative, this means we're going to add dir to the directory stack.
1092 find_ignore_dir_search (const char *dir
)
1094 if (find_ignore_dirs
!= NULL
)
1096 const size_t dlen
= strlen (dir
);
1097 const unsigned char dabs
= g_path_is_absolute (dir
) ? 1 : 0;
1101 for (ignore_dir
= find_ignore_dirs
; *ignore_dir
!= NULL
; ignore_dir
++)
1103 const size_t ilen
= strlen (*ignore_dir
);
1104 const unsigned char iabs
= g_path_is_absolute (*ignore_dir
) ? 2 : 0;
1106 /* ignore dir is too long -- skip it */
1110 /* handle absolute and relative paths */
1111 switch (iabs
| dabs
)
1113 case 0: /* both paths are relative */
1114 case 3: /* both paths are abolute */
1115 /* if ignore dir is not a path of dir -- skip it */
1116 if (strncmp (dir
, *ignore_dir
, ilen
) == 0)
1118 /* be sure that ignore dir is not a part of dir like:
1119 ignore dir is "h", dir is "home" */
1120 if (dir
[ilen
] == '\0' || dir
[ilen
] == PATH_SEP
)
1124 case 1: /* dir is absolute, ignore_dir is relative */
1128 d
= strstr (dir
, *ignore_dir
);
1129 if (d
!= NULL
&& d
[-1] == PATH_SEP
&& (d
[ilen
] == '\0' || d
[ilen
] == PATH_SEP
))
1133 case 2: /* dir is relative, ignore_dir is absolute */
1134 /* FIXME: skip this case */
1136 default: /* this cannot occurs */
1145 /* --------------------------------------------------------------------------------------------- */
1148 find_rotate_dash (const Dlg_head
* h
, gboolean finish
)
1150 static const char rotating_dash
[] = "|/-\\";
1151 static unsigned int pos
= 0;
1155 pos
= (pos
+ 1) % 4;
1156 tty_setcolor (h
->color
[DLG_COLOR_NORMAL
]);
1157 dlg_move (h
, FIND2_Y
- 7, FIND2_X
- 4);
1158 tty_print_char (finish
? ' ' : rotating_dash
[pos
]);
1163 /* --------------------------------------------------------------------------------------------- */
1166 do_search (Dlg_head
* h
)
1168 static struct dirent
*dp
= NULL
;
1169 static DIR *dirp
= NULL
;
1170 static char *directory
= NULL
;
1171 struct stat tmp_stat
;
1172 static int subdirs_left
= 0;
1174 unsigned short count
;
1177 { /* someone forces me to close dirp */
1189 for (count
= 0; count
< 32; count
++)
1199 while (dirp
== NULL
)
1201 vfs_path_t
*tmp_vpath
= NULL
;
1203 tty_setcolor (REVERSE_COLOR
);
1207 tmp_vpath
= pop_directory ();
1208 if (tmp_vpath
== NULL
)
1211 if (ignore_count
== 0)
1212 status_update (_("Finished"));
1215 char msg
[BUF_SMALL
];
1216 g_snprintf (msg
, sizeof (msg
),
1217 ngettext ("Finished (ignored %zd directory)",
1218 "Finished (ignored %zd directories)",
1219 ignore_count
), ignore_count
);
1220 status_update (msg
);
1222 find_rotate_dash (h
, TRUE
);
1227 /* handle absolute ignore dirs here */
1232 tmp
= vfs_path_to_str (tmp_vpath
);
1233 ok
= find_ignore_dir_search (tmp
);
1239 vfs_path_free (tmp_vpath
);
1244 directory
= vfs_path_to_str (tmp_vpath
);
1248 char buffer
[BUF_SMALL
];
1250 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"),
1251 str_trunc (directory
, FIND2_X_USE
));
1252 status_update (buffer
);
1254 /* mc_stat should not be called after mc_opendir
1255 because vfs_s_opendir modifies the st_nlink
1257 if (mc_stat (tmp_vpath
, &tmp_stat
) == 0)
1258 subdirs_left
= tmp_stat
.st_nlink
- 2;
1262 dirp
= mc_opendir (tmp_vpath
);
1263 vfs_path_free (tmp_vpath
);
1264 } /* while (!dirp) */
1266 /* skip invalid filenames */
1267 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1271 if (strcmp (dp
->d_name
, ".") == 0 || strcmp (dp
->d_name
, "..") == 0)
1273 /* skip invalid filenames */
1274 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1280 if (!(options
.skip_hidden
&& (dp
->d_name
[0] == '.')))
1284 if ((subdirs_left
!= 0) && options
.find_recurs
&& (directory
!= NULL
))
1285 { /* Can directory be NULL ? */
1286 /* handle relative ignore dirs here */
1287 if (options
.ignore_dirs_enable
&& find_ignore_dir_search (dp
->d_name
))
1291 vfs_path_t
*tmp_vpath
;
1293 tmp_vpath
= vfs_path_build_filename (directory
, dp
->d_name
, (char *) NULL
);
1295 if (mc_lstat (tmp_vpath
, &tmp_stat
) == 0 && S_ISDIR (tmp_stat
.st_mode
))
1297 push_directory (tmp_vpath
);
1301 vfs_path_free (tmp_vpath
);
1305 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
1306 0, strlen (dp
->d_name
), &bytes_found
);
1310 if (content_pattern
== NULL
)
1311 find_add_match (directory
, dp
->d_name
);
1312 else if (search_content (h
, directory
, dp
->d_name
))
1317 /* skip invalid filenames */
1318 while ((dp
= mc_readdir (dirp
)) != NULL
&& !str_is_valid_string (dp
->d_name
))
1322 find_rotate_dash (h
, FALSE
);
1327 /* --------------------------------------------------------------------------------------------- */
1330 init_find_vars (void)
1337 /* Remove all the items from the stack */
1340 g_strfreev (find_ignore_dirs
);
1341 find_ignore_dirs
= NULL
;
1344 /* --------------------------------------------------------------------------------------------- */
1347 find_do_view_edit (int unparsed_view
, int edit
, char *dir
, char *file
)
1349 char *fullname
= NULL
;
1350 const char *filename
= NULL
;
1352 vfs_path_t
*fullname_vpath
;
1354 if (content_pattern
!= NULL
)
1356 filename
= strchr (file
+ 4, ':') + 1;
1357 line
= atoi (file
+ 4);
1361 filename
= file
+ 4;
1365 fullname_vpath
= vfs_path_build_filename (dir
, filename
, (char *) NULL
);
1367 do_edit_at_line (fullname_vpath
, use_internal_edit
, line
);
1369 view_file_at_line (fullname_vpath
, unparsed_view
, use_internal_view
, line
);
1370 vfs_path_free (fullname_vpath
);
1374 /* --------------------------------------------------------------------------------------------- */
1377 view_edit_currently_selected_file (int unparsed_view
, int edit
)
1382 listbox_get_current (find_list
, &text
, (void **) &dir
);
1384 if ((text
== NULL
) || (dir
== NULL
))
1385 return MSG_NOT_HANDLED
;
1387 find_do_view_edit (unparsed_view
, edit
, dir
, text
);
1391 /* --------------------------------------------------------------------------------------------- */
1394 find_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
1399 if (parm
== KEY_F (3) || parm
== KEY_F (13))
1401 int unparsed_view
= (parm
== KEY_F (13));
1402 return view_edit_currently_selected_file (unparsed_view
, 0);
1404 if (parm
== KEY_F (4))
1406 return view_edit_currently_selected_file (0, 1);
1408 return MSG_NOT_HANDLED
;
1415 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
1419 /* --------------------------------------------------------------------------------------------- */
1420 /** Handles the Stop/Start button in the find window */
1423 start_stop (WButton
* button
, int action
)
1429 set_idle_proc (find_dlg
, running
);
1430 is_start
= !is_start
;
1432 status_update (is_start
? _("Stopped") : _("Searching"));
1433 button_set_text (stop_button
, fbuts
[is_start
? 1 : 0].text
);
1438 /* --------------------------------------------------------------------------------------------- */
1439 /** Handle view command, when invoked as a button */
1442 find_do_view_file (WButton
* button
, int action
)
1447 view_edit_currently_selected_file (0, 0);
1451 /* --------------------------------------------------------------------------------------------- */
1452 /** Handle edit command, when invoked as a button */
1455 find_do_edit_file (WButton
* button
, int action
)
1460 view_edit_currently_selected_file (0, 1);
1464 /* --------------------------------------------------------------------------------------------- */
1470 static gboolean i18n_flag
= FALSE
;
1474 int i
= sizeof (fbuts
) / sizeof (fbuts
[0]);
1477 fbuts
[i
].text
= _(fbuts
[i
].text
);
1478 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1481 fbuts
[2].len
+= 2; /* DEFPUSH_BUTTON */
1484 #endif /* ENABLE_NLS */
1487 * Dynamically place buttons centered within current window size
1490 int l0
= max (fbuts
[0].len
, fbuts
[1].len
);
1491 int l1
= fbuts
[2].len
+ fbuts
[3].len
+ l0
+ fbuts
[4].len
;
1492 int l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
;
1495 /* Check, if both button rows fit within FIND2_X */
1496 FIND2_X
= max (l1
+ 9, COLS
- 16);
1497 FIND2_X
= max (l2
+ 8, FIND2_X
);
1499 /* compute amount of space between buttons for each row */
1500 r1
= (FIND2_X
- 4 - l1
) % 5;
1501 l1
= (FIND2_X
- 4 - l1
) / 5;
1502 r2
= (FIND2_X
- 4 - l2
) % 4;
1503 l2
= (FIND2_X
- 4 - l2
) / 4;
1505 /* ...and finally, place buttons */
1506 fbuts
[2].x
= 2 + r1
/ 2 + l1
;
1507 fbuts
[3].x
= fbuts
[2].x
+ fbuts
[2].len
+ l1
;
1508 fbuts
[0].x
= fbuts
[3].x
+ fbuts
[3].len
+ l1
;
1509 fbuts
[4].x
= fbuts
[0].x
+ l0
+ l1
;
1510 fbuts
[5].x
= 2 + r2
/ 2 + l2
;
1511 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ l2
;
1512 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ l2
;
1516 create_dlg (TRUE
, 0, 0, FIND2_Y
, FIND2_X
, dialog_colors
, find_callback
,
1517 "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
1519 add_widget (find_dlg
,
1520 button_new (FIND2_Y
- 3, fbuts
[7].x
, B_VIEW
, NORMAL_BUTTON
,
1521 fbuts
[7].text
, find_do_edit_file
));
1522 add_widget (find_dlg
,
1523 button_new (FIND2_Y
- 3, fbuts
[6].x
, B_VIEW
, NORMAL_BUTTON
,
1524 fbuts
[6].text
, find_do_view_file
));
1525 add_widget (find_dlg
,
1526 button_new (FIND2_Y
- 3, fbuts
[5].x
, B_PANELIZE
, NORMAL_BUTTON
, fbuts
[5].text
,
1529 add_widget (find_dlg
,
1530 button_new (FIND2_Y
- 4, fbuts
[4].x
, B_CANCEL
, NORMAL_BUTTON
, fbuts
[4].text
, NULL
));
1532 button_new (FIND2_Y
- 4, fbuts
[0].x
, B_STOP
, NORMAL_BUTTON
, fbuts
[0].text
, start_stop
);
1533 add_widget (find_dlg
, stop_button
);
1534 add_widget (find_dlg
,
1535 button_new (FIND2_Y
- 4, fbuts
[3].x
, B_AGAIN
, NORMAL_BUTTON
, fbuts
[3].text
, NULL
));
1536 add_widget (find_dlg
,
1537 button_new (FIND2_Y
- 4, fbuts
[2].x
, B_ENTER
, DEFPUSH_BUTTON
, fbuts
[2].text
, NULL
));
1539 status_label
= label_new (FIND2_Y
- 7, 4, _("Searching"));
1540 add_widget (find_dlg
, status_label
);
1542 found_num_label
= label_new (FIND2_Y
- 6, 4, "");
1543 add_widget (find_dlg
, found_num_label
);
1545 find_list
= listbox_new (2, 2, FIND2_Y
- 10, FIND2_X
- 4, FALSE
, NULL
);
1546 add_widget (find_dlg
, find_list
);
1549 /* --------------------------------------------------------------------------------------------- */
1556 search_content_handle
= mc_search_new (content_pattern
, -1);
1557 if (search_content_handle
)
1559 search_content_handle
->search_type
=
1560 options
.content_regexp
? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
1561 search_content_handle
->is_case_sensitive
= options
.content_case_sens
;
1562 search_content_handle
->whole_words
= options
.content_whole_words
;
1563 search_content_handle
->is_all_charsets
= options
.content_all_charsets
;
1565 search_file_handle
= mc_search_new (find_pattern
, -1);
1566 search_file_handle
->search_type
= options
.file_pattern
? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
1567 search_file_handle
->is_case_sensitive
= options
.file_case_sens
;
1568 search_file_handle
->is_all_charsets
= options
.file_all_charsets
;
1569 search_file_handle
->is_entire_line
= options
.file_pattern
;
1573 set_idle_proc (find_dlg
, 1);
1574 ret
= run_dlg (find_dlg
);
1576 mc_search_free (search_file_handle
);
1577 search_file_handle
= NULL
;
1578 mc_search_free (search_content_handle
);
1579 search_content_handle
= NULL
;
1584 /* --------------------------------------------------------------------------------------------- */
1589 set_idle_proc (find_dlg
, 0);
1590 destroy_dlg (find_dlg
);
1593 /* --------------------------------------------------------------------------------------------- */
1596 do_find (const char *start_dir
, ssize_t start_dir_len
, const char *ignore_dirs
,
1597 const char *pattern
, const char *content
, char **dirname
, char **filename
)
1599 int return_value
= 0;
1600 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1604 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1605 find_pattern
= (char *) pattern
;
1607 content_pattern
= NULL
;
1608 if (options
.content_use
&& content
!= NULL
&& str_is_valid_string (content
))
1609 content_pattern
= g_strdup (content
);
1612 parse_ignore_dirs (ignore_dirs
);
1613 push_directory (vfs_path_from_str (start_dir
));
1615 return_value
= run_process ();
1617 /* Clear variables */
1620 get_list_info (&file_tmp
, &dir_tmp
);
1623 *dirname
= g_strdup (dir_tmp
);
1625 *filename
= g_strdup (file_tmp
);
1627 if (return_value
== B_PANELIZE
&& *filename
)
1629 int status
, link_to_dir
, stale_link
;
1634 dir_list
*list
= ¤t_panel
->dir
;
1637 if (set_zero_dir (list
))
1640 for (i
= 0, entry
= find_list
->list
; entry
!= NULL
; i
++, entry
= g_list_next (entry
))
1642 const char *lc_filename
= NULL
;
1643 WLEntry
*le
= (WLEntry
*) entry
->data
;
1646 if ((le
->text
== NULL
) || (le
->data
== NULL
))
1649 if (content_pattern
!= NULL
)
1650 lc_filename
= strchr (le
->text
+ 4, ':') + 1;
1652 lc_filename
= le
->text
+ 4;
1654 name
= mc_build_filename (le
->data
, lc_filename
, (char *) NULL
);
1655 /* skip initial start dir */
1656 if (start_dir_len
< 0)
1660 p
= name
+ (size_t) start_dir_len
;
1665 status
= handle_path (list
, p
, &st
, next_free
, &link_to_dir
, &stale_link
);
1677 /* don't add files more than once to the panel */
1678 if (content_pattern
!= NULL
&& next_free
> 0
1679 && strcmp (list
->list
[next_free
- 1].fname
, p
) == 0)
1685 if (next_free
== 0) /* first turn i.e clean old list */
1686 panel_clean_dir (current_panel
);
1687 list
->list
[next_free
].fnamelen
= strlen (p
);
1688 list
->list
[next_free
].fname
= g_strndup (p
, list
->list
[next_free
].fnamelen
);
1689 list
->list
[next_free
].f
.marked
= 0;
1690 list
->list
[next_free
].f
.link_to_dir
= link_to_dir
;
1691 list
->list
[next_free
].f
.stale_link
= stale_link
;
1692 list
->list
[next_free
].f
.dir_size_computed
= 0;
1693 list
->list
[next_free
].st
= st
;
1694 list
->list
[next_free
].sort_key
= NULL
;
1695 list
->list
[next_free
].second_sort_key
= NULL
;
1698 if (!(next_free
& 15))
1704 current_panel
->count
= next_free
;
1705 current_panel
->is_panelized
= TRUE
;
1708 if (start_dir_len
< 0)
1711 vfs_path_free (current_panel
->cwd_vpath
);
1712 current_panel
->cwd_vpath
= vfs_path_from_str (PATH_SEP_STR
);
1713 ret
= chdir (PATH_SEP_STR
);
1715 panelize_save_panel (current_panel
);
1719 g_free (content_pattern
);
1721 do_search (NULL
); /* force do_search to release resources */
1725 return return_value
;
1728 /* --------------------------------------------------------------------------------------------- */
1729 /*** public functions ****************************************************************************/
1730 /* --------------------------------------------------------------------------------------------- */
1735 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
, *ignore_dirs
= NULL
;
1736 ssize_t start_dir_len
;
1737 char *filename
= NULL
, *dirname
= NULL
;
1740 while (find_parameters (&start_dir
, &start_dir_len
, &ignore_dirs
, &pattern
, &content
))
1742 if (pattern
[0] == '\0')
1743 break; /* nothing search */
1745 dirname
= filename
= NULL
;
1747 v
= do_find (start_dir
, start_dir_len
, ignore_dirs
, pattern
, content
, &dirname
, &filename
);
1748 g_free (ignore_dirs
);
1753 if (dirname
!= NULL
)
1755 vfs_path_t
*dirname_vpath
;
1757 dirname_vpath
= vfs_path_from_str (dirname
);
1758 do_cd (dirname_vpath
, cd_exact
);
1759 vfs_path_free (dirname_vpath
);
1760 if (filename
!= NULL
)
1761 try_to_select (current_panel
,
1762 filename
+ (content
!= NULL
1763 ? strchr (filename
+ 4, ':') - filename
+ 1 : 4));
1765 else if (filename
!= NULL
)
1767 vfs_path_t
*filename_vpath
;
1769 filename_vpath
= vfs_path_from_str (filename
);
1770 do_cd (filename_vpath
, cd_exact
);
1771 vfs_path_free (filename_vpath
);
1786 if (v
== B_PANELIZE
)
1788 panel_re_sort (current_panel
);
1789 try_to_select (current_panel
, NULL
);
1795 /* --------------------------------------------------------------------------------------------- */