Added counter of ignored dirs.
[pantumic.git] / src / filemanager / find.c
blob908de5ae315e49bb3cee1e17aedb8d32a482aa93
1 /* Find file command for the Midnight Commander
2 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
4 Written 1995 by Miguel de Icaza
6 Complete rewrite.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 /** \file find.c
23 * \brief Source: Find file command
26 #include <config.h>
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <sys/stat.h>
35 #include "lib/global.h"
37 #include "lib/tty/tty.h"
38 #include "lib/tty/key.h"
39 #include "lib/skin.h"
40 #include "lib/search.h"
41 #include "lib/mcconfig.h"
42 #include "lib/strutil.h"
43 #include "lib/widget.h"
44 #include "lib/vfs/mc-vfs/vfs.h"
45 #include "lib/util.h" /* canonicalize_pathname() */
47 #include "src/setup.h" /* verbose */
48 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
49 #include "src/main.h" /* do_cd */
51 #include "dir.h"
52 #include "cmd.h" /* view_file_at_line */
53 #include "midnight.h" /* current_panel */
54 #include "boxes.h"
55 #include "layout.h" /* mc_refresh() */
57 #include "find.h"
59 /*** global variables ****************************************************************************/
61 /*** file scope macro definitions ****************************************************************/
63 /* Size of the find window */
64 #define FIND2_Y (LINES - 4)
66 #define FIND2_X_USE (FIND2_X - 20)
68 /*** file scope type declarations ****************************************************************/
70 /* A couple of extra messages we need */
71 enum
73 B_STOP = B_USER + 1,
74 B_AGAIN,
75 B_PANELIZE,
76 B_TREE,
77 B_VIEW
80 typedef enum
82 FIND_CONT = 0,
83 FIND_SUSPEND,
84 FIND_ABORT
85 } FindProgressStatus;
87 /* find file options */
88 typedef struct
90 /* file name options */
91 gboolean file_case_sens;
92 gboolean file_pattern;
93 gboolean find_recurs;
94 gboolean skip_hidden;
95 gboolean file_all_charsets;
97 /* file content options */
98 gboolean content_use;
99 gboolean content_case_sens;
100 gboolean content_regexp;
101 gboolean content_first_hit;
102 gboolean content_whole_words;
103 gboolean content_all_charsets;
104 } find_file_options_t;
106 /*** file scope variables ************************************************************************/
108 /* Parsed ignore dirs */
109 static char **find_ignore_dirs = NULL;
111 /* Size of the find parameters window */
112 #if HAVE_CHARSET
113 static int FIND_Y = 17;
114 #else
115 static int FIND_Y = 16;
116 #endif
117 static int FIND_X = 68;
119 static int FIND2_X = 64;
121 /* static variables to remember find parameters */
122 static WInput *in_start; /* Start path */
123 static WInput *in_name; /* Filename */
124 static WInput *in_with; /* Text */
125 static WLabel *content_label; /* 'Content:' label */
126 static WCheck *file_case_sens_cbox; /* "case sensitive" checkbox */
127 static WCheck *file_pattern_cbox; /* File name is glob or regexp */
128 static WCheck *recursively_cbox;
129 static WCheck *skip_hidden_cbox;
130 static WCheck *content_use_cbox; /* Take into account the Content field */
131 static WCheck *content_case_sens_cbox; /* "case sensitive" checkbox */
132 static WCheck *content_regexp_cbox; /* "find regular expression" checkbox */
133 static WCheck *content_first_hit_cbox; /* "First hit" checkbox" */
134 static WCheck *content_whole_words_cbox; /* "whole words" checkbox */
135 #ifdef HAVE_CHARSET
136 static WCheck *file_all_charsets_cbox;
137 static WCheck *content_all_charsets_cbox;
138 #endif
140 static gboolean running = FALSE; /* nice flag */
141 static char *find_pattern = NULL; /* Pattern to search */
142 static char *content_pattern = NULL; /* pattern to search inside files; if
143 content_regexp_flag is true, it contains the
144 regex pattern, else the search string. */
145 static unsigned long matches; /* Number of matches */
146 static gboolean is_start = FALSE; /* Status of the start/stop toggle button */
147 static char *old_dir = NULL;
149 /* Where did we stop */
150 static int resuming;
151 static int last_line;
152 static int last_pos;
154 static size_t ignore_count = 0;
156 static Dlg_head *find_dlg; /* The dialog */
157 static WButton *stop_button; /* pointer to the stop button */
158 static WLabel *status_label; /* Finished, Searching etc. */
159 static WLabel *found_num_label; /* Number of found items */
160 static WListbox *find_list; /* Listbox with the file list */
162 /* This keeps track of the directory stack */
163 #if GLIB_CHECK_VERSION (2, 14, 0)
164 static GQueue dir_queue = G_QUEUE_INIT;
165 #else
166 typedef struct dir_stack
168 char *name;
169 struct dir_stack *prev;
170 } dir_stack;
172 static dir_stack *dir_stack_base = 0;
173 #endif /* GLIB_CHECK_VERSION */
175 /* *INDENT-OFF* */
176 static struct
178 const char *text;
179 int len; /* length including space and brackets */
180 int x;
181 } fbuts[] =
183 {N_("&Suspend"), 11, 29},
184 {N_("Con&tinue"), 12, 29},
185 {N_("&Chdir"), 11, 3},
186 {N_("&Again"), 9, 17},
187 {N_("&Quit"), 8, 43},
188 {N_("Pane&lize"), 12, 3},
189 {N_("&View - F3"), 13, 20},
190 {N_("&Edit - F4"), 13, 38}
192 /* *INDENT-ON* */
194 static find_file_options_t options = {
195 TRUE, TRUE, TRUE, FALSE, FALSE,
196 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE
199 static char *in_start_dir = INPUT_LAST_TEXT;
201 static mc_search_t *search_file_handle = NULL;
202 static mc_search_t *search_content_handle = NULL;
204 /*** file scope functions ************************************************************************/
206 static void
207 find_load_options (void)
209 static gboolean loaded = FALSE;
210 char *ignore_dirs;
212 if (loaded)
213 return;
215 loaded = TRUE;
217 /* Back compatibility: try load old parameter at first */
218 ignore_dirs = mc_config_get_string (mc_main_config, "Misc", "find_ignore_dirs", "");
219 if (ignore_dirs[0] != '\0')
221 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
222 mc_config_set_string (mc_main_config, "FindFile", "ignore_dirs", ignore_dirs);
224 g_free (ignore_dirs);
225 mc_config_del_key (mc_main_config, "Misc", "find_ignore_dirs");
227 /* Then load new parameters */
228 ignore_dirs = mc_config_get_string (mc_main_config, "FindFile", "ignore_dirs", "");
229 if (ignore_dirs[0] != '\0')
231 g_strfreev (find_ignore_dirs);
232 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
234 g_free (ignore_dirs);
236 if (find_ignore_dirs != NULL)
238 /* Values like '/foo::/bar: produce holes in list.
239 Find and remove them */
240 size_t r = 0, w = 0; /* read and write iterators */
242 for (; find_ignore_dirs[r] != NULL; r++)
244 if (find_ignore_dirs[r][0] == '\0')
246 /* empty entry -- skip it */
247 g_free (find_ignore_dirs[r]);
248 find_ignore_dirs[r] = NULL;
249 continue;
252 if (r != w)
254 /* copy entry to the previous free array cell */
255 find_ignore_dirs[w] = find_ignore_dirs[r];
256 find_ignore_dirs[r] = NULL;
259 canonicalize_pathname (find_ignore_dirs[w]);
260 if (find_ignore_dirs[w][0] != '\0')
261 w++;
262 else
264 g_free (find_ignore_dirs[w]);
265 find_ignore_dirs[w] = NULL;
269 if (find_ignore_dirs[0] == NULL)
271 g_strfreev (find_ignore_dirs);
272 find_ignore_dirs = NULL;
276 options.file_case_sens =
277 mc_config_get_bool (mc_main_config, "FindFile", "file_case_sens", TRUE);
278 options.file_pattern =
279 mc_config_get_bool (mc_main_config, "FindFile", "file_shell_pattern", TRUE);
280 options.find_recurs = mc_config_get_bool (mc_main_config, "FindFile", "file_find_recurs", TRUE);
281 options.skip_hidden =
282 mc_config_get_bool (mc_main_config, "FindFile", "file_skip_hidden", FALSE);
283 options.file_all_charsets =
284 mc_config_get_bool (mc_main_config, "FindFile", "file_all_charsets", FALSE);
285 options.content_use = mc_config_get_bool (mc_main_config, "FindFile", "content_use", FALSE);
286 options.content_case_sens =
287 mc_config_get_bool (mc_main_config, "FindFile", "content_case_sens", TRUE);
288 options.content_regexp =
289 mc_config_get_bool (mc_main_config, "FindFile", "content_regexp", FALSE);
290 options.content_first_hit =
291 mc_config_get_bool (mc_main_config, "FindFile", "content_first_hit", FALSE);
292 options.content_whole_words =
293 mc_config_get_bool (mc_main_config, "FindFile", "content_whole_words", FALSE);
294 options.content_all_charsets =
295 mc_config_get_bool (mc_main_config, "FindFile", "content_all_charsets", FALSE);
298 /* --------------------------------------------------------------------------------------------- */
300 static void
301 find_save_options (void)
303 mc_config_set_bool (mc_main_config, "FindFile", "file_case_sens", options.file_case_sens);
304 mc_config_set_bool (mc_main_config, "FindFile", "file_shell_pattern", options.file_pattern);
305 mc_config_set_bool (mc_main_config, "FindFile", "file_find_recurs", options.find_recurs);
306 mc_config_set_bool (mc_main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
307 mc_config_set_bool (mc_main_config, "FindFile", "file_all_charsets", options.file_all_charsets);
308 mc_config_set_bool (mc_main_config, "FindFile", "content_use", options.content_use);
309 mc_config_set_bool (mc_main_config, "FindFile", "content_case_sens", options.content_case_sens);
310 mc_config_set_bool (mc_main_config, "FindFile", "content_regexp", options.content_regexp);
311 mc_config_set_bool (mc_main_config, "FindFile", "content_first_hit", options.content_first_hit);
312 mc_config_set_bool (mc_main_config, "FindFile", "content_whole_words",
313 options.content_whole_words);
314 mc_config_set_bool (mc_main_config, "FindFile", "content_all_charsets",
315 options.content_all_charsets);
318 /* --------------------------------------------------------------------------------------------- */
320 static inline char *
321 add_to_list (const char *text, void *data)
323 return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data);
326 /* --------------------------------------------------------------------------------------------- */
328 static inline void
329 stop_idle (void *data)
331 set_idle_proc (data, 0);
334 /* --------------------------------------------------------------------------------------------- */
336 static inline void
337 status_update (const char *text)
339 label_set_text (status_label, text);
342 /* --------------------------------------------------------------------------------------------- */
344 static void
345 found_num_update (void)
347 char buffer[BUF_TINY];
348 g_snprintf (buffer, sizeof (buffer), _("Found: %ld"), matches);
349 label_set_text (found_num_label, buffer);
352 /* --------------------------------------------------------------------------------------------- */
354 static void
355 get_list_info (char **file, char **dir)
357 listbox_get_current (find_list, file, (void **) dir);
360 /* --------------------------------------------------------------------------------------------- */
361 /** check regular expression */
363 static gboolean
364 find_check_regexp (const char *r)
366 mc_search_t *search;
367 gboolean regexp_ok = FALSE;
369 search = mc_search_new (r, -1);
371 if (search != NULL)
373 search->search_type = MC_SEARCH_T_REGEX;
374 regexp_ok = mc_search_prepare (search);
375 mc_search_free (search);
378 return regexp_ok;
381 /* --------------------------------------------------------------------------------------------- */
383 * Callback for the parameter dialog.
384 * Validate regex, prevent closing the dialog if it's invalid.
387 static cb_ret_t
388 find_parm_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
390 switch (msg)
392 case DLG_ACTION:
393 if (sender == (Widget *) content_use_cbox)
395 gboolean disable = !(content_use_cbox->state & C_BOOL);
397 widget_disable (content_label->widget, disable);
398 send_message ((Widget *) content_label, WIDGET_DRAW, 0);
399 widget_disable (in_with->widget, disable);
400 send_message ((Widget *) in_with, WIDGET_DRAW, 0);
401 widget_disable (content_first_hit_cbox->widget, disable);
402 send_message ((Widget *) content_first_hit_cbox, WIDGET_DRAW, 0);
403 widget_disable (content_regexp_cbox->widget, disable);
404 send_message ((Widget *) content_regexp_cbox, WIDGET_DRAW, 0);
405 widget_disable (content_case_sens_cbox->widget, disable);
406 send_message ((Widget *) content_case_sens_cbox, WIDGET_DRAW, 0);
407 #ifdef HAVE_CHARSET
408 widget_disable (content_all_charsets_cbox->widget, disable);
409 send_message ((Widget *) content_all_charsets_cbox, WIDGET_DRAW, 0);
410 #endif
411 widget_disable (content_whole_words_cbox->widget, disable);
412 send_message ((Widget *) content_whole_words_cbox, WIDGET_DRAW, 0);
414 return MSG_HANDLED;
417 return MSG_NOT_HANDLED;
420 case DLG_VALIDATE:
421 if (h->ret_value != B_ENTER)
422 return MSG_HANDLED;
424 /* check filename regexp */
425 if (!(file_pattern_cbox->state & C_BOOL)
426 && (in_name->buffer[0] != '\0') && !find_check_regexp (in_name->buffer))
428 h->state = DLG_ACTIVE; /* Don't stop the dialog */
429 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
430 dlg_select_widget (in_name);
431 return MSG_HANDLED;
434 /* check content regexp */
435 if ((content_use_cbox->state & C_BOOL) && (content_regexp_cbox->state & C_BOOL)
436 && (in_with->buffer[0] != '\0') && !find_check_regexp (in_with->buffer))
438 h->state = DLG_ACTIVE; /* Don't stop the dialog */
439 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
440 dlg_select_widget (in_with);
441 return MSG_HANDLED;
444 return MSG_HANDLED;
446 default:
447 return default_dlg_callback (h, sender, msg, parm, data);
451 /* --------------------------------------------------------------------------------------------- */
453 * find_parameters: gets information from the user
455 * If the return value is TRUE, then the following holds:
457 * START_DIR and PATTERN are pointers to char * and upon return they
458 * contain the information provided by the user.
460 * CONTENT holds a strdup of the contents specified by the user if he
461 * asked for them or 0 if not (note, this is different from the
462 * behavior for the other two parameters.
466 static gboolean
467 find_parameters (char **start_dir, char **pattern, char **content)
469 gboolean return_value;
471 /* file name */
472 const char *file_case_label = N_("Cas&e sensitive");
473 const char *file_pattern_label = N_("&Using shell patterns");
474 const char *file_recurs_label = N_("&Find recursively");
475 const char *file_skip_hidden_label = N_("S&kip hidden");
476 #ifdef HAVE_CHARSET
477 const char *file_all_charsets_label = N_("&All charsets");
478 #endif
480 /* file content */
481 const char *content_use_label = N_("Sea&rch for content");
482 const char *content_case_label = N_("Case sens&itive");
483 const char *content_regexp_label = N_("Re&gular expression");
484 const char *content_first_hit_label = N_("Fir&st hit");
485 const char *content_whole_words_label = N_("&Whole words");
486 #ifdef HAVE_CHARSET
487 const char *content_all_charsets_label = N_("A&ll charsets");
488 #endif
490 const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
492 int b0, b1, b2;
494 int cbox_position;
495 gboolean disable;
497 #ifdef ENABLE_NLS
499 int i = sizeof (buts) / sizeof (buts[0]);
500 while (i-- != 0)
501 buts[i] = _(buts[i]);
503 file_case_label = _(file_case_label);
504 file_pattern_label = _(file_pattern_label);
505 file_recurs_label = _(file_recurs_label);
506 file_skip_hidden_label = _(file_skip_hidden_label);
507 #ifdef HAVE_CHARSET
508 file_all_charsets_label = _(file_all_charsets_label);
509 content_all_charsets_label = _(content_all_charsets_label);
510 #endif
511 content_use_label = _(content_use_label);
512 content_case_label = _(content_case_label);
513 content_regexp_label = _(content_regexp_label);
514 content_first_hit_label = _(content_first_hit_label);
515 content_whole_words_label = _(content_whole_words_label);
517 #endif /* ENABLE_NLS */
519 b0 = str_term_width1 (buts[0]) + 6; /* default button */
520 b1 = str_term_width1 (buts[1]) + 4;
521 b2 = str_term_width1 (buts[2]) + 4;
523 find_load_options ();
525 if (in_start_dir == NULL)
526 in_start_dir = g_strdup (".");
528 disable = !options.content_use;
530 find_dlg =
531 create_dlg (TRUE, 0, 0, FIND_Y, FIND_X, dialog_colors,
532 find_parm_callback, "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
534 add_widget (find_dlg,
535 button_new (FIND_Y - 3, FIND_X * 3 / 4 - b1 / 2, B_CANCEL, NORMAL_BUTTON, buts[1],
536 0));
537 add_widget (find_dlg,
538 button_new (FIND_Y - 3, FIND_X / 4 - b0 / 2, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
540 cbox_position = FIND_Y - 5;
542 content_first_hit_cbox =
543 check_new (cbox_position--, FIND_X / 2 + 1, options.content_first_hit,
544 content_first_hit_label);
545 widget_disable (content_first_hit_cbox->widget, disable);
546 add_widget (find_dlg, content_first_hit_cbox);
548 content_whole_words_cbox =
549 check_new (cbox_position--, FIND_X / 2 + 1, options.content_whole_words,
550 content_whole_words_label);
551 widget_disable (content_whole_words_cbox->widget, disable);
552 add_widget (find_dlg, content_whole_words_cbox);
554 #ifdef HAVE_CHARSET
555 content_all_charsets_cbox = check_new (cbox_position--, FIND_X / 2 + 1,
556 options.content_all_charsets,
557 content_all_charsets_label);
558 widget_disable (content_all_charsets_cbox->widget, disable);
559 add_widget (find_dlg, content_all_charsets_cbox);
560 #endif
562 content_case_sens_cbox =
563 check_new (cbox_position--, FIND_X / 2 + 1, options.content_case_sens, content_case_label);
564 widget_disable (content_case_sens_cbox->widget, disable);
565 add_widget (find_dlg, content_case_sens_cbox);
567 content_regexp_cbox =
568 check_new (cbox_position--, FIND_X / 2 + 1, options.content_regexp, content_regexp_label);
569 widget_disable (content_regexp_cbox->widget, disable);
570 add_widget (find_dlg, content_regexp_cbox);
572 cbox_position = FIND_Y - 6;
574 skip_hidden_cbox = check_new (cbox_position--, 3, options.skip_hidden, file_skip_hidden_label);
575 add_widget (find_dlg, skip_hidden_cbox);
577 #ifdef HAVE_CHARSET
578 file_all_charsets_cbox =
579 check_new (cbox_position--, 3, options.file_all_charsets, file_all_charsets_label);
580 add_widget (find_dlg, file_all_charsets_cbox);
581 #endif
583 file_case_sens_cbox = check_new (cbox_position--, 3, options.file_case_sens, file_case_label);
584 add_widget (find_dlg, file_case_sens_cbox);
586 file_pattern_cbox = check_new (cbox_position--, 3, options.file_pattern, file_pattern_label);
587 add_widget (find_dlg, file_pattern_cbox);
589 recursively_cbox = check_new (cbox_position, 3, options.find_recurs, file_recurs_label);
590 add_widget (find_dlg, recursively_cbox);
592 /* This checkbox is located in the second column */
593 content_use_cbox =
594 check_new (cbox_position, FIND_X / 2 + 1, options.content_use, content_use_label);
595 add_widget (find_dlg, content_use_cbox);
597 in_with =
598 input_new (6, FIND_X / 2 + 1, input_get_default_colors (), FIND_X / 2 - 4, INPUT_LAST_TEXT,
599 MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_DEFAULT);
600 widget_disable (in_with->widget, disable);
601 add_widget (find_dlg, in_with);
603 content_label = label_new (5, FIND_X / 2 + 1, _("Content:"));
604 widget_disable (content_label->widget, disable);
605 add_widget (find_dlg, content_label);
607 in_name = input_new (6, 3, input_get_default_colors (),
608 FIND_X / 2 - 4, INPUT_LAST_TEXT, "name", INPUT_COMPLETE_DEFAULT);
609 add_widget (find_dlg, in_name);
610 add_widget (find_dlg, label_new (5, 3, _("File name:")));
612 add_widget (find_dlg, button_new (3, FIND_X - b2 - 2, B_TREE, NORMAL_BUTTON, buts[2], 0));
614 in_start = input_new (3, 3, input_get_default_colors (),
615 FIND_X - b2 - 6, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
616 add_widget (find_dlg, in_start);
617 add_widget (find_dlg, label_new (2, 3, _("Start at:")));
619 find_par_start:
620 dlg_select_widget (in_name);
622 switch (run_dlg (find_dlg))
624 case B_CANCEL:
625 return_value = FALSE;
626 break;
628 case B_TREE:
630 const char *temp_dir = in_start->buffer;
632 if ((temp_dir[0] == '\0') || ((temp_dir[0] == '.') && (temp_dir[1] == '\0')))
633 temp_dir = current_panel->cwd;
635 if (in_start_dir != INPUT_LAST_TEXT)
636 g_free (in_start_dir);
637 in_start_dir = tree_box (temp_dir);
638 if (in_start_dir == NULL)
639 in_start_dir = g_strdup (temp_dir);
641 input_assign_text (in_start, in_start_dir);
643 /* Warning: Dreadful goto */
644 goto find_par_start;
647 default:
648 #ifdef HAVE_CHARSET
649 options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
650 options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
651 #endif
652 options.content_use = content_use_cbox->state & C_BOOL;
653 options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
654 options.content_regexp = content_regexp_cbox->state & C_BOOL;
655 options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
656 options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
657 options.find_recurs = recursively_cbox->state & C_BOOL;
658 options.file_pattern = file_pattern_cbox->state & C_BOOL;
659 options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
660 options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
662 *content = (options.content_use && in_with->buffer[0] != '\0')
663 ? g_strdup (in_with->buffer) : NULL;
664 *start_dir = in_start->buffer[0] != '\0' ? in_start->buffer : (char *) ".";
665 *pattern = g_strdup (in_name->buffer);
666 if (in_start_dir != INPUT_LAST_TEXT)
667 g_free (in_start_dir);
668 in_start_dir = g_strdup (*start_dir);
669 if ((*start_dir)[0] == '.' && (*start_dir)[1] == '\0')
670 *start_dir = g_strdup (current_panel->cwd);
671 else if (g_path_is_absolute (*start_dir))
672 *start_dir = g_strdup (*start_dir);
673 else
674 *start_dir = g_build_filename (current_panel->cwd, *start_dir, (char *) NULL);
676 canonicalize_pathname (*start_dir);
678 find_save_options ();
680 return_value = TRUE;
683 destroy_dlg (find_dlg);
685 return return_value;
688 /* --------------------------------------------------------------------------------------------- */
690 #if GLIB_CHECK_VERSION (2, 14, 0)
691 static inline void
692 push_directory (const char *dir)
694 g_queue_push_head (&dir_queue, (void *) dir);
697 /* --------------------------------------------------------------------------------------------- */
699 static inline char *
700 pop_directory (void)
702 return (char *) g_queue_pop_tail (&dir_queue);
705 /* --------------------------------------------------------------------------------------------- */
706 /** Remove all the items from the stack */
708 static void
709 clear_stack (void)
711 g_queue_foreach (&dir_queue, (GFunc) g_free, NULL);
712 g_queue_clear (&dir_queue);
715 /* --------------------------------------------------------------------------------------------- */
717 #else /* GLIB_CHECK_VERSION */
718 static void
719 push_directory (const char *dir)
721 dir_stack *new;
723 new = g_new (dir_stack, 1);
724 new->name = (char *) dir;
725 new->prev = dir_stack_base;
726 dir_stack_base = new;
729 /* --------------------------------------------------------------------------------------------- */
731 static char *
732 pop_directory (void)
734 char *name = NULL;
736 if (dir_stack_base != NULL)
738 dir_stack *next;
739 name = dir_stack_base->name;
740 next = dir_stack_base->prev;
741 g_free (dir_stack_base);
742 dir_stack_base = next;
745 return name;
748 /* --------------------------------------------------------------------------------------------- */
749 /** Remove all the items from the stack */
751 static void
752 clear_stack (void)
754 char *dir = NULL;
755 while ((dir = pop_directory ()) != NULL)
756 g_free (dir);
758 #endif /* GLIB_CHECK_VERSION */
760 /* --------------------------------------------------------------------------------------------- */
762 static void
763 insert_file (const char *dir, const char *file)
765 char *tmp_name = NULL;
766 static char *dirname = NULL;
768 while (dir[0] == PATH_SEP && dir[1] == PATH_SEP)
769 dir++;
771 if (old_dir)
773 if (strcmp (old_dir, dir))
775 g_free (old_dir);
776 old_dir = g_strdup (dir);
777 dirname = add_to_list (dir, NULL);
780 else
782 old_dir = g_strdup (dir);
783 dirname = add_to_list (dir, NULL);
786 tmp_name = g_strdup_printf (" %s", file);
787 add_to_list (tmp_name, dirname);
788 g_free (tmp_name);
791 /* --------------------------------------------------------------------------------------------- */
793 static void
794 find_add_match (const char *dir, const char *file)
796 insert_file (dir, file);
798 /* Don't scroll */
799 if (matches == 0)
800 listbox_select_first (find_list);
801 send_message (&find_list->widget, WIDGET_DRAW, 0);
803 matches++;
804 found_num_update ();
807 /* --------------------------------------------------------------------------------------------- */
809 * get_line_at:
811 * Returns malloced null-terminated line from file file_fd.
812 * Input is buffered in buf_size long buffer.
813 * Current pos in buf is stored in pos.
814 * n_read - number of read chars.
815 * has_newline - is there newline ?
818 static char *
819 get_line_at (int file_fd, char *buf, int buf_size, int *pos, int *n_read, gboolean * has_newline)
821 char *buffer = NULL;
822 int buffer_size = 0;
823 char ch = 0;
824 int i = 0;
826 for (;;)
828 if (*pos >= *n_read)
830 *pos = 0;
831 *n_read = mc_read (file_fd, buf, buf_size);
832 if (*n_read <= 0)
833 break;
836 ch = buf[(*pos)++];
837 if (ch == '\0')
839 /* skip possible leading zero(s) */
840 if (i == 0)
841 continue;
842 break;
845 if (i >= buffer_size - 1)
846 buffer = g_realloc (buffer, buffer_size += 80);
848 /* Strip newline */
849 if (ch == '\n')
850 break;
852 buffer[i++] = ch;
855 *has_newline = (ch != '\0');
857 if (buffer != NULL)
858 buffer[i] = '\0';
860 return buffer;
863 /* --------------------------------------------------------------------------------------------- */
865 static FindProgressStatus
866 check_find_events (Dlg_head * h)
868 Gpm_Event event;
869 int c;
871 event.x = -1;
872 c = tty_get_event (&event, h->mouse_status == MOU_REPEAT, FALSE);
873 if (c != EV_NONE)
875 dlg_process_event (h, c, &event);
876 if (h->ret_value == B_ENTER
877 || h->ret_value == B_CANCEL || h->ret_value == B_AGAIN || h->ret_value == B_PANELIZE)
879 /* dialog terminated */
880 return FIND_ABORT;
882 if (!(h->flags & DLG_WANT_IDLE))
884 /* searching suspended */
885 return FIND_SUSPEND;
889 return FIND_CONT;
892 /* --------------------------------------------------------------------------------------------- */
894 * search_content:
896 * Search the content_pattern string in the DIRECTORY/FILE.
897 * It will add the found entries to the find listbox.
899 * returns FALSE if do_search should look for another file
900 * TRUE if do_search should exit and proceed to the event handler
903 static gboolean
904 search_content (Dlg_head * h, const char *directory, const char *filename)
906 struct stat s;
907 char buffer[BUF_4K];
908 char *fname = NULL;
909 int file_fd;
910 gboolean ret_val = FALSE;
912 fname = concat_dir_and_file (directory, filename);
914 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode))
916 g_free (fname);
917 return FALSE;
920 file_fd = mc_open (fname, O_RDONLY);
921 g_free (fname);
923 if (file_fd == -1)
924 return FALSE;
926 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), str_trunc (filename, FIND2_X_USE));
928 status_update (buffer);
929 mc_refresh ();
931 tty_enable_interrupt_key ();
932 tty_got_interrupt ();
935 int line = 1;
936 int pos = 0;
937 int n_read = 0;
938 gboolean has_newline;
939 char *p = NULL;
940 gboolean found = FALSE;
941 gsize found_len;
942 char result[BUF_MEDIUM];
944 if (resuming)
946 /* We've been previously suspended, start from the previous position */
947 resuming = 0;
948 line = last_line;
949 pos = last_pos;
951 while (!ret_val
952 && (p = get_line_at (file_fd, buffer, sizeof (buffer),
953 &pos, &n_read, &has_newline)) != NULL)
955 if (!found /* Search in binary line once */
956 && mc_search_run (search_content_handle,
957 (const void *) p, 0, strlen (p), &found_len))
959 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
960 find_add_match (directory, result);
961 found = TRUE;
963 g_free (p);
965 if (found && options.content_first_hit)
966 break;
968 if (has_newline)
970 found = FALSE;
971 line++;
974 if ((line & 0xff) == 0)
976 FindProgressStatus res;
977 res = check_find_events (h);
978 switch (res)
980 case FIND_ABORT:
981 stop_idle (h);
982 ret_val = TRUE;
983 break;
984 case FIND_SUSPEND:
985 resuming = 1;
986 last_line = line;
987 last_pos = pos;
988 ret_val = TRUE;
989 break;
990 default:
991 break;
996 tty_disable_interrupt_key ();
997 mc_close (file_fd);
998 return ret_val;
1001 /* --------------------------------------------------------------------------------------------- */
1004 If dir is absolute, this means we're within dir and searching file here.
1005 If dir is relative, this means we're going to add dir to the directory stack.
1007 static gboolean
1008 find_ignore_dir_search (const char *dir)
1010 if (find_ignore_dirs != NULL)
1012 const size_t dlen = strlen (dir);
1013 const unsigned char dabs = g_path_is_absolute (dir) ? 1 : 0;
1015 char **ignore_dir;
1017 for (ignore_dir = find_ignore_dirs; *ignore_dir != NULL; ignore_dir++)
1019 const size_t ilen = strlen (*ignore_dir);
1020 const unsigned char iabs = g_path_is_absolute (*ignore_dir) ? 2 : 0;
1022 /* ignore dir is too long -- skip it */
1023 if (dlen < ilen)
1024 continue;
1026 /* handle absolute and relative paths */
1027 switch (iabs | dabs)
1029 case 0: /* both paths are relative */
1030 case 3: /* both paths are abolute */
1031 /* if ignore dir is not a path of dir -- skip it */
1032 if (strncmp (dir, *ignore_dir, ilen) == 0)
1034 /* be sure that ignore dir is not a part of dir like:
1035 ignore dir is "h", dir is "home" */
1036 if (dir[ilen] == '\0' || dir[ilen] == PATH_SEP)
1037 return TRUE;
1039 break;
1040 case 1: /* dir is absolute, ignore_dir is relative */
1042 char *d;
1044 d = strstr (dir, *ignore_dir);
1045 if (d != NULL && d[-1] == PATH_SEP && (d[ilen] == '\0' || d[ilen] == PATH_SEP))
1046 return TRUE;
1048 break;
1049 case 2: /* dir is relative, ignore_dir is absolute */
1050 /* FIXME: skip this case */
1051 break;
1052 default: /* this cannot occurs */
1053 return FALSE;
1058 return FALSE;
1061 /* --------------------------------------------------------------------------------------------- */
1063 static void
1064 find_rotate_dash (const Dlg_head * h, gboolean finish)
1066 static const char rotating_dash[] = "|/-\\";
1067 static unsigned int pos = 0;
1069 if (verbose)
1071 pos = (pos + 1) % 4;
1072 tty_setcolor (h->color[DLG_COLOR_NORMAL]);
1073 dlg_move (h, FIND2_Y - 7, FIND2_X - 4);
1074 tty_print_char (finish ? ' ' : rotating_dash[pos]);
1075 mc_refresh ();
1079 /* --------------------------------------------------------------------------------------------- */
1081 static int
1082 do_search (Dlg_head * h)
1084 static struct dirent *dp = NULL;
1085 static DIR *dirp = NULL;
1086 static char *directory = NULL;
1087 struct stat tmp_stat;
1088 static int subdirs_left = 0;
1089 gsize bytes_found;
1090 unsigned short count;
1092 if (h == NULL)
1093 { /* someone forces me to close dirp */
1094 if (dirp != NULL)
1096 mc_closedir (dirp);
1097 dirp = NULL;
1099 g_free (directory);
1100 directory = NULL;
1101 dp = NULL;
1102 return 1;
1105 for (count = 0; count < 32; count++)
1107 while (dp == NULL)
1109 if (dirp != NULL)
1111 mc_closedir (dirp);
1112 dirp = NULL;
1115 while (dirp == NULL)
1117 char *tmp = NULL;
1119 tty_setcolor (REVERSE_COLOR);
1121 while (TRUE)
1123 tmp = pop_directory ();
1124 if (tmp == NULL)
1126 running = FALSE;
1127 if (ignore_count == 0)
1128 status_update (_("Finished"));
1129 else
1131 char msg[BUF_SMALL];
1132 g_snprintf (msg, sizeof (msg),
1133 ngettext ("Finished (ignored %zd directory)",
1134 "Finished (ignored %zd directories)",
1135 ignore_count), ignore_count);
1136 status_update (msg);
1138 find_rotate_dash (h, TRUE);
1139 stop_idle (h);
1140 return 0;
1143 /* handle absolute ignore dirs here */
1144 if (!find_ignore_dir_search (tmp))
1145 break;
1147 g_free (tmp);
1148 ignore_count++;
1151 g_free (directory);
1152 directory = tmp;
1154 if (verbose)
1156 char buffer[BUF_SMALL];
1158 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
1159 str_trunc (directory, FIND2_X_USE));
1160 status_update (buffer);
1162 /* mc_stat should not be called after mc_opendir
1163 because vfs_s_opendir modifies the st_nlink
1165 if (mc_stat (directory, &tmp_stat) == 0)
1166 subdirs_left = tmp_stat.st_nlink - 2;
1167 else
1168 subdirs_left = 0;
1170 dirp = mc_opendir (directory);
1171 } /* while (!dirp) */
1173 /* skip invalid filenames */
1174 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1176 } /* while (!dp) */
1178 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
1180 /* skip invalid filenames */
1181 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1184 return 1;
1187 if (!(options.skip_hidden && (dp->d_name[0] == '.')))
1189 gboolean search_ok;
1191 if ((subdirs_left != 0) && options.find_recurs && (directory != NULL))
1192 { /* Can directory be NULL ? */
1193 /* handle relative ignore dirs here */
1194 if (find_ignore_dir_search (dp->d_name))
1195 ignore_count++;
1196 else
1198 char *tmp_name;
1200 tmp_name = g_build_filename (directory, dp->d_name, (char *) NULL);
1202 if (mc_lstat (tmp_name, &tmp_stat) == 0 && S_ISDIR (tmp_stat.st_mode))
1204 push_directory (tmp_name);
1205 subdirs_left--;
1207 else
1208 g_free (tmp_name);
1212 search_ok = mc_search_run (search_file_handle, dp->d_name,
1213 0, strlen (dp->d_name), &bytes_found);
1215 if (search_ok)
1217 if (content_pattern == NULL)
1218 find_add_match (directory, dp->d_name);
1219 else if (search_content (h, directory, dp->d_name))
1220 return 1;
1224 /* skip invalid filenames */
1225 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1227 } /* for */
1229 find_rotate_dash (h, FALSE);
1231 return 1;
1234 /* --------------------------------------------------------------------------------------------- */
1236 static void
1237 init_find_vars (void)
1239 g_free (old_dir);
1240 old_dir = NULL;
1241 matches = 0;
1242 ignore_count = 0;
1244 /* Remove all the items from the stack */
1245 clear_stack ();
1248 /* --------------------------------------------------------------------------------------------- */
1250 static char *
1251 make_fullname (const char *dirname, const char *filename)
1254 if (strcmp (dirname, ".") == 0 || strcmp (dirname, "." PATH_SEP_STR) == 0)
1255 return g_strdup (filename);
1256 if (strncmp (dirname, "." PATH_SEP_STR, 2) == 0)
1257 return concat_dir_and_file (dirname + 2, filename);
1258 return concat_dir_and_file (dirname, filename);
1261 /* --------------------------------------------------------------------------------------------- */
1263 static void
1264 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
1266 char *fullname = NULL;
1267 const char *filename = NULL;
1268 int line;
1270 if (content_pattern != NULL)
1272 filename = strchr (file + 4, ':') + 1;
1273 line = atoi (file + 4);
1275 else
1277 filename = file + 4;
1278 line = 0;
1281 fullname = make_fullname (dir, filename);
1282 if (edit)
1283 do_edit_at_line (fullname, use_internal_edit, line);
1284 else
1285 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
1286 g_free (fullname);
1289 /* --------------------------------------------------------------------------------------------- */
1291 static cb_ret_t
1292 view_edit_currently_selected_file (int unparsed_view, int edit)
1294 char *dir = NULL;
1295 char *text = NULL;
1297 listbox_get_current (find_list, &text, (void **) &dir);
1299 if ((text == NULL) || (dir == NULL))
1300 return MSG_NOT_HANDLED;
1302 find_do_view_edit (unparsed_view, edit, dir, text);
1303 return MSG_HANDLED;
1306 /* --------------------------------------------------------------------------------------------- */
1308 static cb_ret_t
1309 find_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
1311 switch (msg)
1313 case DLG_KEY:
1314 if (parm == KEY_F (3) || parm == KEY_F (13))
1316 int unparsed_view = (parm == KEY_F (13));
1317 return view_edit_currently_selected_file (unparsed_view, 0);
1319 if (parm == KEY_F (4))
1321 return view_edit_currently_selected_file (0, 1);
1323 return MSG_NOT_HANDLED;
1325 case DLG_IDLE:
1326 do_search (h);
1327 return MSG_HANDLED;
1329 default:
1330 return default_dlg_callback (h, sender, msg, parm, data);
1334 /* --------------------------------------------------------------------------------------------- */
1335 /** Handles the Stop/Start button in the find window */
1337 static int
1338 start_stop (WButton * button, int action)
1340 (void) button;
1341 (void) action;
1343 running = is_start;
1344 set_idle_proc (find_dlg, running);
1345 is_start = !is_start;
1347 status_update (is_start ? _("Stopped") : _("Searching"));
1348 button_set_text (stop_button, fbuts[is_start ? 1 : 0].text);
1350 return 0;
1353 /* --------------------------------------------------------------------------------------------- */
1354 /** Handle view command, when invoked as a button */
1356 static int
1357 find_do_view_file (WButton * button, int action)
1359 (void) button;
1360 (void) action;
1362 view_edit_currently_selected_file (0, 0);
1363 return 0;
1366 /* --------------------------------------------------------------------------------------------- */
1367 /** Handle edit command, when invoked as a button */
1369 static int
1370 find_do_edit_file (WButton * button, int action)
1372 (void) button;
1373 (void) action;
1375 view_edit_currently_selected_file (0, 1);
1376 return 0;
1379 /* --------------------------------------------------------------------------------------------- */
1381 static void
1382 setup_gui (void)
1384 #ifdef ENABLE_NLS
1385 static gboolean i18n_flag = FALSE;
1387 if (!i18n_flag)
1389 int i = sizeof (fbuts) / sizeof (fbuts[0]);
1390 while (i-- != 0)
1392 fbuts[i].text = _(fbuts[i].text);
1393 fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1396 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
1397 i18n_flag = TRUE;
1399 #endif /* ENABLE_NLS */
1402 * Dynamically place buttons centered within current window size
1405 int l0 = max (fbuts[0].len, fbuts[1].len);
1406 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
1407 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
1408 int r1, r2;
1410 /* Check, if both button rows fit within FIND2_X */
1411 FIND2_X = max (l1 + 9, COLS - 16);
1412 FIND2_X = max (l2 + 8, FIND2_X);
1414 /* compute amount of space between buttons for each row */
1415 r1 = (FIND2_X - 4 - l1) % 5;
1416 l1 = (FIND2_X - 4 - l1) / 5;
1417 r2 = (FIND2_X - 4 - l2) % 4;
1418 l2 = (FIND2_X - 4 - l2) / 4;
1420 /* ...and finally, place buttons */
1421 fbuts[2].x = 2 + r1 / 2 + l1;
1422 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
1423 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
1424 fbuts[4].x = fbuts[0].x + l0 + l1;
1425 fbuts[5].x = 2 + r2 / 2 + l2;
1426 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
1427 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
1430 find_dlg =
1431 create_dlg (TRUE, 0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
1432 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
1434 add_widget (find_dlg,
1435 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
1436 fbuts[7].text, find_do_edit_file));
1437 add_widget (find_dlg,
1438 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
1439 fbuts[6].text, find_do_view_file));
1440 add_widget (find_dlg,
1441 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON, fbuts[5].text,
1442 NULL));
1444 add_widget (find_dlg,
1445 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON, fbuts[4].text, NULL));
1446 stop_button =
1447 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON, fbuts[0].text, start_stop);
1448 add_widget (find_dlg, stop_button);
1449 add_widget (find_dlg,
1450 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON, fbuts[3].text, NULL));
1451 add_widget (find_dlg,
1452 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON, fbuts[2].text, NULL));
1454 status_label = label_new (FIND2_Y - 7, 4, _("Searching"));
1455 add_widget (find_dlg, status_label);
1457 found_num_label = label_new (FIND2_Y - 6, 4, "");
1458 add_widget (find_dlg, found_num_label);
1460 find_list = listbox_new (2, 2, FIND2_Y - 10, FIND2_X - 4, FALSE, NULL);
1461 add_widget (find_dlg, find_list);
1464 /* --------------------------------------------------------------------------------------------- */
1466 static int
1467 run_process (void)
1469 int ret;
1471 search_content_handle = mc_search_new (content_pattern, -1);
1472 if (search_content_handle)
1474 search_content_handle->search_type =
1475 options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
1476 search_content_handle->is_case_sensitive = options.content_case_sens;
1477 search_content_handle->whole_words = options.content_whole_words;
1478 search_content_handle->is_all_charsets = options.content_all_charsets;
1480 search_file_handle = mc_search_new (find_pattern, -1);
1481 search_file_handle->search_type = options.file_pattern ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
1482 search_file_handle->is_case_sensitive = options.file_case_sens;
1483 search_file_handle->is_all_charsets = options.file_all_charsets;
1484 search_file_handle->is_entire_line = options.file_pattern;
1486 resuming = 0;
1487 set_idle_proc (find_dlg, 1);
1488 ret = run_dlg (find_dlg);
1490 mc_search_free (search_file_handle);
1491 search_file_handle = NULL;
1492 mc_search_free (search_content_handle);
1493 search_content_handle = NULL;
1495 return ret;
1498 /* --------------------------------------------------------------------------------------------- */
1500 static void
1501 kill_gui (void)
1503 set_idle_proc (find_dlg, 0);
1504 destroy_dlg (find_dlg);
1507 /* --------------------------------------------------------------------------------------------- */
1509 static int
1510 find_file (const char *start_dir, const char *pattern, const char *content,
1511 char **dirname, char **filename)
1513 int return_value = 0;
1514 char *dir_tmp = NULL, *file_tmp = NULL;
1516 setup_gui ();
1518 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1519 find_pattern = (char *) pattern;
1521 content_pattern = NULL;
1522 if (options.content_use && content != NULL && str_is_valid_string (content))
1523 content_pattern = g_strdup (content);
1525 init_find_vars ();
1526 push_directory (start_dir);
1528 return_value = run_process ();
1530 /* Remove all the items from the stack */
1531 clear_stack ();
1533 get_list_info (&file_tmp, &dir_tmp);
1535 if (dir_tmp)
1536 *dirname = g_strdup (dir_tmp);
1537 if (file_tmp)
1538 *filename = g_strdup (file_tmp);
1540 if (return_value == B_PANELIZE && *filename)
1542 int status, link_to_dir, stale_link;
1543 int next_free = 0;
1544 int i;
1545 struct stat st;
1546 GList *entry;
1547 dir_list *list = &current_panel->dir;
1548 char *name = NULL;
1550 for (i = 0, entry = find_list->list; entry != NULL; i++, entry = g_list_next (entry))
1552 const char *lc_filename = NULL;
1553 WLEntry *le = (WLEntry *) entry->data;
1555 if ((le->text == NULL) || (le->data == NULL))
1556 continue;
1558 if (content_pattern != NULL)
1559 lc_filename = strchr (le->text + 4, ':') + 1;
1560 else
1561 lc_filename = le->text + 4;
1563 name = make_fullname (le->data, lc_filename);
1564 status = handle_path (list, name, &st, next_free, &link_to_dir, &stale_link);
1565 if (status == 0)
1567 g_free (name);
1568 continue;
1570 if (status == -1)
1572 g_free (name);
1573 break;
1576 /* don't add files more than once to the panel */
1577 if (content_pattern != NULL && next_free > 0
1578 && strcmp (list->list[next_free - 1].fname, name) == 0)
1580 g_free (name);
1581 continue;
1584 if (!next_free) /* first turn i.e clean old list */
1585 panel_clean_dir (current_panel);
1586 list->list[next_free].fnamelen = strlen (name);
1587 list->list[next_free].fname = name;
1588 list->list[next_free].f.marked = 0;
1589 list->list[next_free].f.link_to_dir = link_to_dir;
1590 list->list[next_free].f.stale_link = stale_link;
1591 list->list[next_free].f.dir_size_computed = 0;
1592 list->list[next_free].st = st;
1593 list->list[next_free].sort_key = NULL;
1594 list->list[next_free].second_sort_key = NULL;
1595 next_free++;
1596 if (!(next_free & 15))
1597 rotate_dash ();
1600 if (next_free)
1602 current_panel->count = next_free;
1603 current_panel->is_panelized = 1;
1605 if (start_dir[0] == PATH_SEP)
1607 int ret;
1608 strcpy (current_panel->cwd, PATH_SEP_STR);
1609 ret = chdir (PATH_SEP_STR);
1614 g_free (content_pattern);
1615 kill_gui ();
1616 do_search (NULL); /* force do_search to release resources */
1617 g_free (old_dir);
1618 old_dir = NULL;
1620 return return_value;
1623 /* --------------------------------------------------------------------------------------------- */
1624 /*** public functions ****************************************************************************/
1625 /* --------------------------------------------------------------------------------------------- */
1627 void
1628 do_find (void)
1630 char *start_dir = NULL, *pattern = NULL, *content = NULL;
1631 char *filename = NULL, *dirname = NULL;
1632 int v;
1633 gboolean dir_and_file_set;
1635 while (find_parameters (&start_dir, &pattern, &content))
1637 if (pattern[0] == '\0')
1638 break; /* nothing search */
1640 dirname = filename = NULL;
1641 is_start = FALSE;
1642 v = find_file (start_dir, pattern, content, &dirname, &filename);
1643 g_free (pattern);
1645 if (v == B_ENTER)
1647 if (dirname != NULL)
1649 do_cd (dirname, cd_exact);
1650 if (filename != NULL)
1651 try_to_select (current_panel,
1652 filename + (content != NULL
1653 ? strchr (filename + 4, ':') - filename + 1 : 4));
1655 else if (filename != NULL)
1656 do_cd (filename, cd_exact);
1658 g_free (dirname);
1659 g_free (filename);
1660 break;
1663 g_free (content);
1664 dir_and_file_set = (dirname != NULL) && (filename != NULL);
1665 g_free (dirname);
1666 g_free (filename);
1668 if (v == B_CANCEL)
1669 break;
1671 if (v == B_PANELIZE)
1673 if (dir_and_file_set)
1675 try_to_select (current_panel, NULL);
1676 panel_re_sort (current_panel);
1677 try_to_select (current_panel, NULL);
1679 break;
1684 /* --------------------------------------------------------------------------------------------- */