find.c (search_content): type accuracy of return value.
[midnight-commander.git] / src / filemanager / find.c
blob1719ec79caf3a82546a0532912d782a68bc25222
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/util.h" /* canonicalize_pathname() */
38 #include "lib/tty/tty.h"
39 #include "lib/tty/key.h"
40 #include "lib/skin.h"
41 #include "lib/search.h"
42 #include "lib/mcconfig.h"
43 #include "lib/vfs/mc-vfs/vfs.h"
44 #include "lib/strutil.h"
45 #include "lib/util.h"
46 #include "lib/widget.h"
48 #include "src/setup.h" /* verbose */
49 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
50 #include "src/main.h" /* do_cd */
52 #include "dir.h"
53 #include "cmd.h" /* view_file_at_line */
54 #include "midnight.h" /* current_panel */
55 #include "boxes.h"
56 #include "layout.h" /* mc_refresh() */
58 #include "find.h"
60 /*** global variables ****************************************************************************/
62 /* List of directories to be ignored, separated by ':' */
63 char **find_ignore_dirs = NULL;
65 /*** file scope macro definitions ****************************************************************/
67 /* Size of the find window */
68 #define FIND2_Y (LINES - 4)
70 #define FIND2_X_USE (FIND2_X - 20)
72 /*** file scope type declarations ****************************************************************/
74 /* A couple of extra messages we need */
75 enum
77 B_STOP = B_USER + 1,
78 B_AGAIN,
79 B_PANELIZE,
80 B_TREE,
81 B_VIEW
84 typedef enum
86 FIND_CONT = 0,
87 FIND_SUSPEND,
88 FIND_ABORT
89 } FindProgressStatus;
91 /* find file options */
92 typedef struct
94 /* file name options */
95 gboolean file_case_sens;
96 gboolean file_pattern;
97 gboolean find_recurs;
98 gboolean skip_hidden;
99 gboolean file_all_charsets;
101 /* file content options */
102 gboolean content_use;
103 gboolean content_case_sens;
104 gboolean content_regexp;
105 gboolean content_first_hit;
106 gboolean content_whole_words;
107 gboolean content_all_charsets;
108 } find_file_options_t;
110 /*** file scope variables ************************************************************************/
112 /* Size of the find parameters window */
113 #if HAVE_CHARSET
114 static int FIND_Y = 17;
115 #else
116 static int FIND_Y = 16;
117 #endif
118 static int FIND_X = 68;
120 static int FIND2_X = 64;
122 /* static variables to remember find parameters */
123 static WInput *in_start; /* Start path */
124 static WInput *in_name; /* Filename */
125 static WInput *in_with; /* Text */
126 static WLabel *content_label; /* 'Content:' label */
127 static WCheck *file_case_sens_cbox; /* "case sensitive" checkbox */
128 static WCheck *file_pattern_cbox; /* File name is glob or regexp */
129 static WCheck *recursively_cbox;
130 static WCheck *skip_hidden_cbox;
131 static WCheck *content_use_cbox; /* Take into account the Content field */
132 static WCheck *content_case_sens_cbox; /* "case sensitive" checkbox */
133 static WCheck *content_regexp_cbox; /* "find regular expression" checkbox */
134 static WCheck *content_first_hit_cbox; /* "First hit" checkbox" */
135 static WCheck *content_whole_words_cbox; /* "whole words" checkbox */
136 #ifdef HAVE_CHARSET
137 static WCheck *file_all_charsets_cbox;
138 static WCheck *content_all_charsets_cbox;
139 #endif
141 static gboolean running = FALSE; /* nice flag */
142 static char *find_pattern = NULL; /* Pattern to search */
143 static char *content_pattern = NULL; /* pattern to search inside files; if
144 content_regexp_flag is true, it contains the
145 regex pattern, else the search string. */
146 static unsigned long matches; /* Number of matches */
147 static gboolean is_start = FALSE; /* Status of the start/stop toggle button */
148 static char *old_dir = NULL;
150 /* Where did we stop */
151 static int resuming;
152 static int last_line;
153 static int last_pos;
155 static Dlg_head *find_dlg; /* The dialog */
156 static WButton *stop_button; /* pointer to the stop button */
157 static WLabel *status_label; /* Finished, Searching etc. */
158 static WLabel *found_num_label; /* Number of found items */
159 static WListbox *find_list; /* Listbox with the file list */
161 /* This keeps track of the directory stack */
162 #if GLIB_CHECK_VERSION (2, 14, 0)
163 static GQueue dir_queue = G_QUEUE_INIT;
164 #else
165 typedef struct dir_stack
167 char *name;
168 struct dir_stack *prev;
169 } dir_stack;
171 static dir_stack *dir_stack_base = 0;
172 #endif /* GLIB_CHECK_VERSION */
174 /* *INDENT-OFF* */
175 static struct
177 const char *text;
178 int len; /* length including space and brackets */
179 int x;
180 } fbuts[] =
182 {N_("&Suspend"), 11, 29},
183 {N_("Con&tinue"), 12, 29},
184 {N_("&Chdir"), 11, 3},
185 {N_("&Again"), 9, 17},
186 {N_("&Quit"), 8, 43},
187 {N_("Pane&lize"), 12, 3},
188 {N_("&View - F3"), 13, 20},
189 {N_("&Edit - F4"), 13, 38}
191 /* *INDENT-ON* */
193 static find_file_options_t options = {
194 TRUE, TRUE, TRUE, FALSE, FALSE,
195 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE
198 static char *in_start_dir = INPUT_LAST_TEXT;
200 static mc_search_t *search_file_handle = NULL;
201 static mc_search_t *search_content_handle = NULL;
203 /*** file scope functions ************************************************************************/
205 static int
206 find_ignore_dirs_cmp (const void *d1, const void *d2)
208 return strcmp (*(const char **) d1, *(const char **) d2);
211 /* --------------------------------------------------------------------------------------------- */
213 static void
214 find_load_options (void)
216 static gboolean loaded = FALSE;
217 char *ignore_dirs;
219 if (loaded)
220 return;
222 loaded = TRUE;
224 /* Back compatibility: try load old parameter at first */
225 ignore_dirs = mc_config_get_string (mc_main_config, "Misc", "find_ignore_dirs", "");
226 if (ignore_dirs[0] != '\0')
228 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
229 mc_config_set_string (mc_main_config, "FindFile", "ignore_dirs", ignore_dirs);
231 g_free (ignore_dirs);
232 mc_config_del_key (mc_main_config, "Misc", "find_ignore_dirs");
234 /* Then load new parameters */
235 ignore_dirs = mc_config_get_string (mc_main_config, "FindFile", "ignore_dirs", "");
236 if (ignore_dirs[0] != '\0')
238 g_strfreev (find_ignore_dirs);
239 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
241 g_free (ignore_dirs);
243 if (find_ignore_dirs != NULL)
245 /* Values like '/foo::/bar: produce holes in list.
246 Find and remove them */
247 size_t r = 0, w = 0; /* read and write iterators */
249 for (; find_ignore_dirs[r] != NULL; r++)
251 if (find_ignore_dirs[r][0] == '\0')
253 /* empty entry -- skip it */
254 g_free (find_ignore_dirs[r]);
255 find_ignore_dirs[r] = NULL;
256 continue;
259 if (r != w)
261 /* copy entry to the previous free array cell */
262 find_ignore_dirs[w] = find_ignore_dirs[r];
263 find_ignore_dirs[r] = NULL;
266 canonicalize_pathname (find_ignore_dirs[w]);
267 w++;
270 /* sort array */
271 if (find_ignore_dirs[0] != NULL)
272 qsort (find_ignore_dirs, g_strv_length (find_ignore_dirs),
273 sizeof (find_ignore_dirs[0]), &find_ignore_dirs_cmp);
274 else
276 g_strfreev (find_ignore_dirs);
277 find_ignore_dirs = NULL;
281 options.file_case_sens =
282 mc_config_get_bool (mc_main_config, "FindFile", "file_case_sens", TRUE);
283 options.file_pattern =
284 mc_config_get_bool (mc_main_config, "FindFile", "file_shell_pattern", TRUE);
285 options.find_recurs = mc_config_get_bool (mc_main_config, "FindFile", "file_find_recurs", TRUE);
286 options.skip_hidden =
287 mc_config_get_bool (mc_main_config, "FindFile", "file_skip_hidden", FALSE);
288 options.file_all_charsets =
289 mc_config_get_bool (mc_main_config, "FindFile", "file_all_charsets", FALSE);
290 options.content_use = mc_config_get_bool (mc_main_config, "FindFile", "content_use", FALSE);
291 options.content_case_sens =
292 mc_config_get_bool (mc_main_config, "FindFile", "content_case_sens", TRUE);
293 options.content_regexp =
294 mc_config_get_bool (mc_main_config, "FindFile", "content_regexp", FALSE);
295 options.content_first_hit =
296 mc_config_get_bool (mc_main_config, "FindFile", "content_first_hit", FALSE);
297 options.content_whole_words =
298 mc_config_get_bool (mc_main_config, "FindFile", "content_whole_words", FALSE);
299 options.content_all_charsets =
300 mc_config_get_bool (mc_main_config, "FindFile", "content_all_charsets", FALSE);
303 /* --------------------------------------------------------------------------------------------- */
305 static void
306 find_save_options (void)
308 mc_config_set_bool (mc_main_config, "FindFile", "file_case_sens", options.file_case_sens);
309 mc_config_set_bool (mc_main_config, "FindFile", "file_shell_pattern", options.file_pattern);
310 mc_config_set_bool (mc_main_config, "FindFile", "file_find_recurs", options.find_recurs);
311 mc_config_set_bool (mc_main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
312 mc_config_set_bool (mc_main_config, "FindFile", "file_all_charsets", options.file_all_charsets);
313 mc_config_set_bool (mc_main_config, "FindFile", "content_use", options.content_use);
314 mc_config_set_bool (mc_main_config, "FindFile", "content_case_sens", options.content_case_sens);
315 mc_config_set_bool (mc_main_config, "FindFile", "content_regexp", options.content_regexp);
316 mc_config_set_bool (mc_main_config, "FindFile", "content_first_hit", options.content_first_hit);
317 mc_config_set_bool (mc_main_config, "FindFile", "content_whole_words",
318 options.content_whole_words);
319 mc_config_set_bool (mc_main_config, "FindFile", "content_all_charsets",
320 options.content_all_charsets);
323 /* --------------------------------------------------------------------------------------------- */
325 static inline char *
326 add_to_list (const char *text, void *data)
328 return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data);
331 /* --------------------------------------------------------------------------------------------- */
333 static inline void
334 stop_idle (void *data)
336 set_idle_proc (data, 0);
339 /* --------------------------------------------------------------------------------------------- */
341 static inline void
342 status_update (const char *text)
344 label_set_text (status_label, text);
347 /* --------------------------------------------------------------------------------------------- */
349 static void
350 found_num_update (void)
352 char buffer[BUF_TINY];
353 g_snprintf (buffer, sizeof (buffer), _("Found: %ld"), matches);
354 label_set_text (found_num_label, buffer);
357 /* --------------------------------------------------------------------------------------------- */
359 static void
360 get_list_info (char **file, char **dir)
362 listbox_get_current (find_list, file, (void **) dir);
365 /* --------------------------------------------------------------------------------------------- */
366 /** check regular expression */
368 static gboolean
369 find_check_regexp (const char *r)
371 mc_search_t *search;
372 gboolean regexp_ok = FALSE;
374 search = mc_search_new (r, -1);
376 if (search != NULL)
378 search->search_type = MC_SEARCH_T_REGEX;
379 regexp_ok = mc_search_prepare (search);
380 mc_search_free (search);
383 return regexp_ok;
386 /* --------------------------------------------------------------------------------------------- */
388 * Callback for the parameter dialog.
389 * Validate regex, prevent closing the dialog if it's invalid.
392 static cb_ret_t
393 find_parm_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
395 switch (msg)
397 case DLG_ACTION:
398 if (sender == (Widget *) content_use_cbox)
400 gboolean disable = !(content_use_cbox->state & C_BOOL);
402 widget_disable (content_label->widget, disable);
403 send_message ((Widget *) content_label, WIDGET_DRAW, 0);
404 widget_disable (in_with->widget, disable);
405 send_message ((Widget *) in_with, WIDGET_DRAW, 0);
406 widget_disable (content_first_hit_cbox->widget, disable);
407 send_message ((Widget *) content_first_hit_cbox, WIDGET_DRAW, 0);
408 widget_disable (content_regexp_cbox->widget, disable);
409 send_message ((Widget *) content_regexp_cbox, WIDGET_DRAW, 0);
410 widget_disable (content_case_sens_cbox->widget, disable);
411 send_message ((Widget *) content_case_sens_cbox, WIDGET_DRAW, 0);
412 #ifdef HAVE_CHARSET
413 widget_disable (content_all_charsets_cbox->widget, disable);
414 send_message ((Widget *) content_all_charsets_cbox, WIDGET_DRAW, 0);
415 #endif
416 widget_disable (content_whole_words_cbox->widget, disable);
417 send_message ((Widget *) content_whole_words_cbox, WIDGET_DRAW, 0);
419 return MSG_HANDLED;
422 return MSG_NOT_HANDLED;
425 case DLG_VALIDATE:
426 if (h->ret_value != B_ENTER)
427 return MSG_HANDLED;
429 /* check filename regexp */
430 if (!(file_pattern_cbox->state & C_BOOL)
431 && (in_name->buffer[0] != '\0') && !find_check_regexp (in_name->buffer))
433 h->state = DLG_ACTIVE; /* Don't stop the dialog */
434 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
435 dlg_select_widget (in_name);
436 return MSG_HANDLED;
439 /* check content regexp */
440 if ((content_use_cbox->state & C_BOOL) && (content_regexp_cbox->state & C_BOOL)
441 && (in_with->buffer[0] != '\0') && !find_check_regexp (in_with->buffer))
443 h->state = DLG_ACTIVE; /* Don't stop the dialog */
444 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
445 dlg_select_widget (in_with);
446 return MSG_HANDLED;
449 return MSG_HANDLED;
451 default:
452 return default_dlg_callback (h, sender, msg, parm, data);
456 /* --------------------------------------------------------------------------------------------- */
458 * find_parameters: gets information from the user
460 * If the return value is TRUE, then the following holds:
462 * START_DIR and PATTERN are pointers to char * and upon return they
463 * contain the information provided by the user.
465 * CONTENT holds a strdup of the contents specified by the user if he
466 * asked for them or 0 if not (note, this is different from the
467 * behavior for the other two parameters.
471 static gboolean
472 find_parameters (char **start_dir, char **pattern, char **content)
474 gboolean return_value;
476 /* file name */
477 const char *file_case_label = N_("Cas&e sensitive");
478 const char *file_pattern_label = N_("&Using shell patterns");
479 const char *file_recurs_label = N_("&Find recursively");
480 const char *file_skip_hidden_label = N_("S&kip hidden");
481 #ifdef HAVE_CHARSET
482 const char *file_all_charsets_label = N_("&All charsets");
483 #endif
485 /* file content */
486 const char *content_use_label = N_("Sea&rch for content");
487 const char *content_case_label = N_("Case sens&itive");
488 const char *content_regexp_label = N_("Re&gular expression");
489 const char *content_first_hit_label = N_("Fir&st hit");
490 const char *content_whole_words_label = N_("&Whole words");
491 #ifdef HAVE_CHARSET
492 const char *content_all_charsets_label = N_("A&ll charsets");
493 #endif
495 const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
497 int b0, b1, b2;
499 int cbox_position;
500 gboolean disable;
502 #ifdef ENABLE_NLS
504 int i = sizeof (buts) / sizeof (buts[0]);
505 while (i-- != 0)
506 buts[i] = _(buts[i]);
508 file_case_label = _(file_case_label);
509 file_pattern_label = _(file_pattern_label);
510 file_recurs_label = _(file_recurs_label);
511 file_skip_hidden_label = _(file_skip_hidden_label);
512 #ifdef HAVE_CHARSET
513 file_all_charsets_label = _(file_all_charsets_label);
514 content_all_charsets_label = _(content_all_charsets_label);
515 #endif
516 content_use_label = _(content_use_label);
517 content_case_label = _(content_case_label);
518 content_regexp_label = _(content_regexp_label);
519 content_first_hit_label = _(content_first_hit_label);
520 content_whole_words_label = _(content_whole_words_label);
522 #endif /* ENABLE_NLS */
524 b0 = str_term_width1 (buts[0]) + 6; /* default button */
525 b1 = str_term_width1 (buts[1]) + 4;
526 b2 = str_term_width1 (buts[2]) + 4;
528 find_load_options ();
530 if (in_start_dir == NULL)
531 in_start_dir = g_strdup (".");
533 disable = !options.content_use;
535 find_dlg =
536 create_dlg (TRUE, 0, 0, FIND_Y, FIND_X, dialog_colors,
537 find_parm_callback, "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
539 add_widget (find_dlg,
540 button_new (FIND_Y - 3, FIND_X * 3 / 4 - b1 / 2, B_CANCEL, NORMAL_BUTTON, buts[1],
541 0));
542 add_widget (find_dlg,
543 button_new (FIND_Y - 3, FIND_X / 4 - b0 / 2, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
545 cbox_position = FIND_Y - 5;
547 content_first_hit_cbox =
548 check_new (cbox_position--, FIND_X / 2 + 1, options.content_first_hit,
549 content_first_hit_label);
550 widget_disable (content_first_hit_cbox->widget, disable);
551 add_widget (find_dlg, content_first_hit_cbox);
553 content_whole_words_cbox =
554 check_new (cbox_position--, FIND_X / 2 + 1, options.content_whole_words,
555 content_whole_words_label);
556 widget_disable (content_whole_words_cbox->widget, disable);
557 add_widget (find_dlg, content_whole_words_cbox);
559 #ifdef HAVE_CHARSET
560 content_all_charsets_cbox = check_new (cbox_position--, FIND_X / 2 + 1,
561 options.content_all_charsets,
562 content_all_charsets_label);
563 widget_disable (content_all_charsets_cbox->widget, disable);
564 add_widget (find_dlg, content_all_charsets_cbox);
565 #endif
567 content_case_sens_cbox =
568 check_new (cbox_position--, FIND_X / 2 + 1, options.content_case_sens, content_case_label);
569 widget_disable (content_case_sens_cbox->widget, disable);
570 add_widget (find_dlg, content_case_sens_cbox);
572 content_regexp_cbox =
573 check_new (cbox_position--, FIND_X / 2 + 1, options.content_regexp, content_regexp_label);
574 widget_disable (content_regexp_cbox->widget, disable);
575 add_widget (find_dlg, content_regexp_cbox);
577 cbox_position = FIND_Y - 6;
579 skip_hidden_cbox = check_new (cbox_position--, 3, options.skip_hidden, file_skip_hidden_label);
580 add_widget (find_dlg, skip_hidden_cbox);
582 #ifdef HAVE_CHARSET
583 file_all_charsets_cbox =
584 check_new (cbox_position--, 3, options.file_all_charsets, file_all_charsets_label);
585 add_widget (find_dlg, file_all_charsets_cbox);
586 #endif
588 file_case_sens_cbox = check_new (cbox_position--, 3, options.file_case_sens, file_case_label);
589 add_widget (find_dlg, file_case_sens_cbox);
591 file_pattern_cbox = check_new (cbox_position--, 3, options.file_pattern, file_pattern_label);
592 add_widget (find_dlg, file_pattern_cbox);
594 recursively_cbox = check_new (cbox_position, 3, options.find_recurs, file_recurs_label);
595 add_widget (find_dlg, recursively_cbox);
597 /* This checkbox is located in the second column */
598 content_use_cbox =
599 check_new (cbox_position, FIND_X / 2 + 1, options.content_use, content_use_label);
600 add_widget (find_dlg, content_use_cbox);
602 in_with =
603 input_new (6, FIND_X / 2 + 1, input_get_default_colors (), FIND_X / 2 - 4, INPUT_LAST_TEXT,
604 MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_DEFAULT);
605 widget_disable (in_with->widget, disable);
606 add_widget (find_dlg, in_with);
608 content_label = label_new (5, FIND_X / 2 + 1, _("Content:"));
609 widget_disable (content_label->widget, disable);
610 add_widget (find_dlg, content_label);
612 in_name = input_new (6, 3, input_get_default_colors (),
613 FIND_X / 2 - 4, INPUT_LAST_TEXT, "name", INPUT_COMPLETE_DEFAULT);
614 add_widget (find_dlg, in_name);
615 add_widget (find_dlg, label_new (5, 3, _("File name:")));
617 add_widget (find_dlg, button_new (3, FIND_X - b2 - 2, B_TREE, NORMAL_BUTTON, buts[2], 0));
619 in_start = input_new (3, 3, input_get_default_colors (),
620 FIND_X - b2 - 6, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
621 add_widget (find_dlg, in_start);
622 add_widget (find_dlg, label_new (2, 3, _("Start at:")));
624 find_par_start:
625 dlg_select_widget (in_name);
627 switch (run_dlg (find_dlg))
629 case B_CANCEL:
630 return_value = FALSE;
631 break;
633 case B_TREE:
635 const char *temp_dir = in_start->buffer;
637 if ((temp_dir[0] == '\0') || ((temp_dir[0] == '.') && (temp_dir[1] == '\0')))
638 temp_dir = current_panel->cwd;
640 if (in_start_dir != INPUT_LAST_TEXT)
641 g_free (in_start_dir);
642 in_start_dir = tree_box (temp_dir);
643 if (in_start_dir == NULL)
644 in_start_dir = g_strdup (temp_dir);
646 input_assign_text (in_start, in_start_dir);
648 /* Warning: Dreadful goto */
649 goto find_par_start;
652 default:
653 #ifdef HAVE_CHARSET
654 options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
655 options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
656 #endif
657 options.content_use = content_use_cbox->state & C_BOOL;
658 options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
659 options.content_regexp = content_regexp_cbox->state & C_BOOL;
660 options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
661 options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
662 options.find_recurs = recursively_cbox->state & C_BOOL;
663 options.file_pattern = file_pattern_cbox->state & C_BOOL;
664 options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
665 options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
667 *content = (options.content_use && in_with->buffer[0] != '\0')
668 ? g_strdup (in_with->buffer) : NULL;
669 *start_dir = in_start->buffer[0] != '\0' ? in_start->buffer : (char *) ".";
670 *pattern = g_strdup (in_name->buffer);
671 if (in_start_dir != INPUT_LAST_TEXT)
672 g_free (in_start_dir);
673 in_start_dir = g_strdup (*start_dir);
674 if ((*start_dir)[0] == '.' && (*start_dir)[1] == '\0')
675 *start_dir = g_strdup (current_panel->cwd);
676 else if (g_path_is_absolute (*start_dir))
677 *start_dir = g_strdup (*start_dir);
678 else
679 *start_dir = g_build_filename (current_panel->cwd, *start_dir, (char *) NULL);
681 canonicalize_pathname (*start_dir);
683 find_save_options ();
685 return_value = TRUE;
688 destroy_dlg (find_dlg);
690 return return_value;
693 /* --------------------------------------------------------------------------------------------- */
695 #if GLIB_CHECK_VERSION (2, 14, 0)
696 static inline void
697 push_directory (const char *dir)
699 g_queue_push_head (&dir_queue, (void *) dir);
702 /* --------------------------------------------------------------------------------------------- */
704 static inline char *
705 pop_directory (void)
707 return (char *) g_queue_pop_tail (&dir_queue);
710 /* --------------------------------------------------------------------------------------------- */
711 /** Remove all the items from the stack */
713 static void
714 clear_stack (void)
716 g_queue_foreach (&dir_queue, (GFunc) g_free, NULL);
717 g_queue_clear (&dir_queue);
720 /* --------------------------------------------------------------------------------------------- */
722 #else /* GLIB_CHECK_VERSION */
723 static void
724 push_directory (const char *dir)
726 dir_stack *new;
728 new = g_new (dir_stack, 1);
729 new->name = (char *) dir;
730 new->prev = dir_stack_base;
731 dir_stack_base = new;
734 /* --------------------------------------------------------------------------------------------- */
736 static char *
737 pop_directory (void)
739 char *name = NULL;
741 if (dir_stack_base != NULL)
743 dir_stack *next;
744 name = dir_stack_base->name;
745 next = dir_stack_base->prev;
746 g_free (dir_stack_base);
747 dir_stack_base = next;
750 return name;
753 /* --------------------------------------------------------------------------------------------- */
754 /** Remove all the items from the stack */
756 static void
757 clear_stack (void)
759 char *dir = NULL;
760 while ((dir = pop_directory ()) != NULL)
761 g_free (dir);
763 #endif /* GLIB_CHECK_VERSION */
765 /* --------------------------------------------------------------------------------------------- */
767 static void
768 insert_file (const char *dir, const char *file)
770 char *tmp_name = NULL;
771 static char *dirname = NULL;
773 while (dir[0] == PATH_SEP && dir[1] == PATH_SEP)
774 dir++;
776 if (old_dir)
778 if (strcmp (old_dir, dir))
780 g_free (old_dir);
781 old_dir = g_strdup (dir);
782 dirname = add_to_list (dir, NULL);
785 else
787 old_dir = g_strdup (dir);
788 dirname = add_to_list (dir, NULL);
791 tmp_name = g_strdup_printf (" %s", file);
792 add_to_list (tmp_name, dirname);
793 g_free (tmp_name);
796 /* --------------------------------------------------------------------------------------------- */
798 static void
799 find_add_match (const char *dir, const char *file)
801 insert_file (dir, file);
803 /* Don't scroll */
804 if (matches == 0)
805 listbox_select_first (find_list);
806 send_message (&find_list->widget, WIDGET_DRAW, 0);
808 matches++;
809 found_num_update ();
812 /* --------------------------------------------------------------------------------------------- */
814 * get_line_at:
816 * Returns malloced null-terminated line from file file_fd.
817 * Input is buffered in buf_size long buffer.
818 * Current pos in buf is stored in pos.
819 * n_read - number of read chars.
820 * has_newline - is there newline ?
823 static char *
824 get_line_at (int file_fd, char *buf, int buf_size, int *pos, int *n_read, gboolean * has_newline)
826 char *buffer = NULL;
827 int buffer_size = 0;
828 char ch = 0;
829 int i = 0;
831 for (;;)
833 if (*pos >= *n_read)
835 *pos = 0;
836 *n_read = mc_read (file_fd, buf, buf_size);
837 if (*n_read <= 0)
838 break;
841 ch = buf[(*pos)++];
842 if (ch == '\0')
844 /* skip possible leading zero(s) */
845 if (i == 0)
846 continue;
847 break;
850 if (i >= buffer_size - 1)
851 buffer = g_realloc (buffer, buffer_size += 80);
853 /* Strip newline */
854 if (ch == '\n')
855 break;
857 buffer[i++] = ch;
860 *has_newline = (ch != '\0');
862 if (buffer != NULL)
863 buffer[i] = '\0';
865 return buffer;
868 /* --------------------------------------------------------------------------------------------- */
870 static FindProgressStatus
871 check_find_events (Dlg_head * h)
873 Gpm_Event event;
874 int c;
876 event.x = -1;
877 c = tty_get_event (&event, h->mouse_status == MOU_REPEAT, FALSE);
878 if (c != EV_NONE)
880 dlg_process_event (h, c, &event);
881 if (h->ret_value == B_ENTER
882 || h->ret_value == B_CANCEL || h->ret_value == B_AGAIN || h->ret_value == B_PANELIZE)
884 /* dialog terminated */
885 return FIND_ABORT;
887 if (!(h->flags & DLG_WANT_IDLE))
889 /* searching suspended */
890 return FIND_SUSPEND;
894 return FIND_CONT;
897 /* --------------------------------------------------------------------------------------------- */
899 * search_content:
901 * Search the content_pattern string in the DIRECTORY/FILE.
902 * It will add the found entries to the find listbox.
904 * returns FALSE if do_search should look for another file
905 * TRUE if do_search should exit and proceed to the event handler
908 static gboolean
909 search_content (Dlg_head * h, const char *directory, const char *filename)
911 struct stat s;
912 char buffer[BUF_4K];
913 char *fname = NULL;
914 int file_fd;
915 gboolean ret_val = FALSE;
917 fname = concat_dir_and_file (directory, filename);
919 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode))
921 g_free (fname);
922 return FALSE;
925 file_fd = mc_open (fname, O_RDONLY);
926 g_free (fname);
928 if (file_fd == -1)
929 return FALSE;
931 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), str_trunc (filename, FIND2_X_USE));
933 status_update (buffer);
934 mc_refresh ();
936 tty_enable_interrupt_key ();
937 tty_got_interrupt ();
940 int line = 1;
941 int pos = 0;
942 int n_read = 0;
943 gboolean has_newline;
944 char *p = NULL;
945 gboolean found = FALSE;
946 gsize found_len;
947 char result[BUF_MEDIUM];
949 if (resuming)
951 /* We've been previously suspended, start from the previous position */
952 resuming = 0;
953 line = last_line;
954 pos = last_pos;
956 while (!ret_val
957 && (p = get_line_at (file_fd, buffer, sizeof (buffer),
958 &pos, &n_read, &has_newline)) != NULL)
960 if (!found /* Search in binary line once */
961 && mc_search_run (search_content_handle,
962 (const void *) p, 0, strlen (p), &found_len))
964 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
965 find_add_match (directory, result);
966 found = TRUE;
968 g_free (p);
970 if (found && options.content_first_hit)
971 break;
973 if (has_newline)
975 found = FALSE;
976 line++;
979 if ((line & 0xff) == 0)
981 FindProgressStatus res;
982 res = check_find_events (h);
983 switch (res)
985 case FIND_ABORT:
986 stop_idle (h);
987 ret_val = TRUE;
988 break;
989 case FIND_SUSPEND:
990 resuming = 1;
991 last_line = line;
992 last_pos = pos;
993 ret_val = TRUE;
994 break;
995 default:
996 break;
1001 tty_disable_interrupt_key ();
1002 mc_close (file_fd);
1003 return ret_val;
1006 /* --------------------------------------------------------------------------------------------- */
1008 static inline gboolean
1009 find_ignore_dir_search (const char *dir)
1011 if (find_ignore_dirs != NULL)
1013 const size_t dlen = strlen (dir);
1014 char **ignore_dir;
1016 for (ignore_dir = find_ignore_dirs; *ignore_dir != NULL; ignore_dir++)
1018 const size_t ilen = strlen (*ignore_dir);
1020 if (dlen < ilen)
1021 continue; /* ignore dir is too long -- skip it */
1023 if (strncmp (dir, *ignore_dir, ilen) != 0)
1024 continue; /* strings are different -- skip ignore_dir */
1026 /* be sure than ignore_dir is not a part of dir like:
1027 ignore_dir is "/h", dir is "/home" */
1028 if (dir[ilen] == PATH_SEP || dir[ilen] == '\0')
1029 return TRUE;
1033 return FALSE;
1036 /* --------------------------------------------------------------------------------------------- */
1038 static void
1039 find_rotate_dash (const Dlg_head * h, gboolean finish)
1041 static const char rotating_dash[] = "|/-\\";
1042 static unsigned int pos = 0;
1044 if (verbose)
1046 pos = (pos + 1) % 4;
1047 tty_setcolor (h->color[DLG_COLOR_NORMAL]);
1048 dlg_move (h, FIND2_Y - 7, FIND2_X - 4);
1049 tty_print_char (finish ? ' ' : rotating_dash[pos]);
1050 mc_refresh ();
1054 /* --------------------------------------------------------------------------------------------- */
1056 static int
1057 do_search (Dlg_head * h)
1059 static struct dirent *dp = NULL;
1060 static DIR *dirp = NULL;
1061 static char *directory = NULL;
1062 struct stat tmp_stat;
1063 static int subdirs_left = 0;
1064 gsize bytes_found;
1065 unsigned short count;
1067 if (h == NULL)
1068 { /* someone forces me to close dirp */
1069 if (dirp != NULL)
1071 mc_closedir (dirp);
1072 dirp = NULL;
1074 g_free (directory);
1075 directory = NULL;
1076 dp = NULL;
1077 return 1;
1080 for (count = 0; count < 32; count++)
1082 while (dp == NULL)
1084 if (dirp != NULL)
1086 mc_closedir (dirp);
1087 dirp = NULL;
1090 while (dirp == NULL)
1092 char *tmp = NULL;
1094 tty_setcolor (REVERSE_COLOR);
1096 while (TRUE)
1098 tmp = pop_directory ();
1099 if (tmp == NULL)
1101 running = FALSE;
1102 status_update (_("Finished"));
1103 find_rotate_dash (h, TRUE);
1104 stop_idle (h);
1105 return 0;
1108 if (!find_ignore_dir_search (tmp))
1109 break;
1111 g_free (tmp);
1114 g_free (directory);
1115 directory = tmp;
1117 if (verbose)
1119 char buffer[BUF_SMALL];
1121 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
1122 str_trunc (directory, FIND2_X_USE));
1123 status_update (buffer);
1125 /* mc_stat should not be called after mc_opendir
1126 because vfs_s_opendir modifies the st_nlink
1128 if (mc_stat (directory, &tmp_stat) == 0)
1129 subdirs_left = tmp_stat.st_nlink - 2;
1130 else
1131 subdirs_left = 0;
1133 dirp = mc_opendir (directory);
1134 } /* while (!dirp) */
1136 /* skip invalid filenames */
1137 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1139 } /* while (!dp) */
1141 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
1143 /* skip invalid filenames */
1144 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1147 return 1;
1150 if (!(options.skip_hidden && (dp->d_name[0] == '.')))
1152 gboolean search_ok;
1154 if ((subdirs_left != 0) && options.find_recurs && (directory != NULL))
1155 { /* Can directory be NULL ? */
1156 char *tmp_name = concat_dir_and_file (directory, dp->d_name);
1157 if (mc_lstat (tmp_name, &tmp_stat) == 0 && S_ISDIR (tmp_stat.st_mode))
1159 push_directory (tmp_name);
1160 subdirs_left--;
1162 else
1163 g_free (tmp_name);
1166 search_ok = mc_search_run (search_file_handle, dp->d_name,
1167 0, strlen (dp->d_name), &bytes_found);
1169 if (search_ok)
1171 if (content_pattern == NULL)
1172 find_add_match (directory, dp->d_name);
1173 else if (search_content (h, directory, dp->d_name))
1174 return 1;
1178 /* skip invalid filenames */
1179 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1181 } /* for */
1183 find_rotate_dash (h, FALSE);
1185 return 1;
1188 /* --------------------------------------------------------------------------------------------- */
1190 static void
1191 init_find_vars (void)
1193 g_free (old_dir);
1194 old_dir = NULL;
1195 matches = 0;
1197 /* Remove all the items from the stack */
1198 clear_stack ();
1201 /* --------------------------------------------------------------------------------------------- */
1203 static char *
1204 make_fullname (const char *dirname, const char *filename)
1207 if (strcmp (dirname, ".") == 0 || strcmp (dirname, "." PATH_SEP_STR) == 0)
1208 return g_strdup (filename);
1209 if (strncmp (dirname, "." PATH_SEP_STR, 2) == 0)
1210 return concat_dir_and_file (dirname + 2, filename);
1211 return concat_dir_and_file (dirname, filename);
1214 /* --------------------------------------------------------------------------------------------- */
1216 static void
1217 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
1219 char *fullname = NULL;
1220 const char *filename = NULL;
1221 int line;
1223 if (content_pattern != NULL)
1225 filename = strchr (file + 4, ':') + 1;
1226 line = atoi (file + 4);
1228 else
1230 filename = file + 4;
1231 line = 0;
1234 fullname = make_fullname (dir, filename);
1235 if (edit)
1236 do_edit_at_line (fullname, use_internal_edit, line);
1237 else
1238 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
1239 g_free (fullname);
1242 /* --------------------------------------------------------------------------------------------- */
1244 static cb_ret_t
1245 view_edit_currently_selected_file (int unparsed_view, int edit)
1247 char *dir = NULL;
1248 char *text = NULL;
1250 listbox_get_current (find_list, &text, (void **) &dir);
1252 if ((text == NULL) || (dir == NULL))
1253 return MSG_NOT_HANDLED;
1255 find_do_view_edit (unparsed_view, edit, dir, text);
1256 return MSG_HANDLED;
1259 /* --------------------------------------------------------------------------------------------- */
1261 static cb_ret_t
1262 find_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
1264 switch (msg)
1266 case DLG_KEY:
1267 if (parm == KEY_F (3) || parm == KEY_F (13))
1269 int unparsed_view = (parm == KEY_F (13));
1270 return view_edit_currently_selected_file (unparsed_view, 0);
1272 if (parm == KEY_F (4))
1274 return view_edit_currently_selected_file (0, 1);
1276 return MSG_NOT_HANDLED;
1278 case DLG_IDLE:
1279 do_search (h);
1280 return MSG_HANDLED;
1282 default:
1283 return default_dlg_callback (h, sender, msg, parm, data);
1287 /* --------------------------------------------------------------------------------------------- */
1288 /** Handles the Stop/Start button in the find window */
1290 static int
1291 start_stop (WButton * button, int action)
1293 (void) button;
1294 (void) action;
1296 running = is_start;
1297 set_idle_proc (find_dlg, running);
1298 is_start = !is_start;
1300 status_update (is_start ? _("Stopped") : _("Searching"));
1301 button_set_text (stop_button, fbuts[is_start ? 1 : 0].text);
1303 return 0;
1306 /* --------------------------------------------------------------------------------------------- */
1307 /** Handle view command, when invoked as a button */
1309 static int
1310 find_do_view_file (WButton * button, int action)
1312 (void) button;
1313 (void) action;
1315 view_edit_currently_selected_file (0, 0);
1316 return 0;
1319 /* --------------------------------------------------------------------------------------------- */
1320 /** Handle edit command, when invoked as a button */
1322 static int
1323 find_do_edit_file (WButton * button, int action)
1325 (void) button;
1326 (void) action;
1328 view_edit_currently_selected_file (0, 1);
1329 return 0;
1332 /* --------------------------------------------------------------------------------------------- */
1334 static void
1335 setup_gui (void)
1337 #ifdef ENABLE_NLS
1338 static gboolean i18n_flag = FALSE;
1340 if (!i18n_flag)
1342 int i = sizeof (fbuts) / sizeof (fbuts[0]);
1343 while (i-- != 0)
1345 fbuts[i].text = _(fbuts[i].text);
1346 fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1349 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
1350 i18n_flag = TRUE;
1352 #endif /* ENABLE_NLS */
1355 * Dynamically place buttons centered within current window size
1358 int l0 = max (fbuts[0].len, fbuts[1].len);
1359 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
1360 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
1361 int r1, r2;
1363 /* Check, if both button rows fit within FIND2_X */
1364 FIND2_X = max (l1 + 9, COLS - 16);
1365 FIND2_X = max (l2 + 8, FIND2_X);
1367 /* compute amount of space between buttons for each row */
1368 r1 = (FIND2_X - 4 - l1) % 5;
1369 l1 = (FIND2_X - 4 - l1) / 5;
1370 r2 = (FIND2_X - 4 - l2) % 4;
1371 l2 = (FIND2_X - 4 - l2) / 4;
1373 /* ...and finally, place buttons */
1374 fbuts[2].x = 2 + r1 / 2 + l1;
1375 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
1376 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
1377 fbuts[4].x = fbuts[0].x + l0 + l1;
1378 fbuts[5].x = 2 + r2 / 2 + l2;
1379 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
1380 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
1383 find_dlg =
1384 create_dlg (TRUE, 0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
1385 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
1387 add_widget (find_dlg,
1388 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
1389 fbuts[7].text, find_do_edit_file));
1390 add_widget (find_dlg,
1391 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
1392 fbuts[6].text, find_do_view_file));
1393 add_widget (find_dlg,
1394 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON, fbuts[5].text,
1395 NULL));
1397 add_widget (find_dlg,
1398 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON, fbuts[4].text, NULL));
1399 stop_button =
1400 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON, fbuts[0].text, start_stop);
1401 add_widget (find_dlg, stop_button);
1402 add_widget (find_dlg,
1403 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON, fbuts[3].text, NULL));
1404 add_widget (find_dlg,
1405 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON, fbuts[2].text, NULL));
1407 status_label = label_new (FIND2_Y - 7, 4, _("Searching"));
1408 add_widget (find_dlg, status_label);
1410 found_num_label = label_new (FIND2_Y - 6, 4, "");
1411 add_widget (find_dlg, found_num_label);
1413 find_list = listbox_new (2, 2, FIND2_Y - 10, FIND2_X - 4, FALSE, NULL);
1414 add_widget (find_dlg, find_list);
1417 /* --------------------------------------------------------------------------------------------- */
1419 static int
1420 run_process (void)
1422 int ret;
1424 search_content_handle = mc_search_new (content_pattern, -1);
1425 if (search_content_handle)
1427 search_content_handle->search_type =
1428 options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
1429 search_content_handle->is_case_sensitive = options.content_case_sens;
1430 search_content_handle->whole_words = options.content_whole_words;
1431 search_content_handle->is_all_charsets = options.content_all_charsets;
1433 search_file_handle = mc_search_new (find_pattern, -1);
1434 search_file_handle->search_type = options.file_pattern ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
1435 search_file_handle->is_case_sensitive = options.file_case_sens;
1436 search_file_handle->is_all_charsets = options.file_all_charsets;
1437 search_file_handle->is_entire_line = options.file_pattern;
1439 resuming = 0;
1440 set_idle_proc (find_dlg, 1);
1441 ret = run_dlg (find_dlg);
1443 mc_search_free (search_file_handle);
1444 search_file_handle = NULL;
1445 mc_search_free (search_content_handle);
1446 search_content_handle = NULL;
1448 return ret;
1451 /* --------------------------------------------------------------------------------------------- */
1453 static void
1454 kill_gui (void)
1456 set_idle_proc (find_dlg, 0);
1457 destroy_dlg (find_dlg);
1460 /* --------------------------------------------------------------------------------------------- */
1462 static int
1463 find_file (const char *start_dir, const char *pattern, const char *content,
1464 char **dirname, char **filename)
1466 int return_value = 0;
1467 char *dir_tmp = NULL, *file_tmp = NULL;
1469 setup_gui ();
1471 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1472 find_pattern = (char *) pattern;
1474 content_pattern = NULL;
1475 if (options.content_use && content != NULL && str_is_valid_string (content))
1476 content_pattern = g_strdup (content);
1478 init_find_vars ();
1479 push_directory (start_dir);
1481 return_value = run_process ();
1483 /* Remove all the items from the stack */
1484 clear_stack ();
1486 get_list_info (&file_tmp, &dir_tmp);
1488 if (dir_tmp)
1489 *dirname = g_strdup (dir_tmp);
1490 if (file_tmp)
1491 *filename = g_strdup (file_tmp);
1493 if (return_value == B_PANELIZE && *filename)
1495 int status, link_to_dir, stale_link;
1496 int next_free = 0;
1497 int i;
1498 struct stat st;
1499 GList *entry;
1500 dir_list *list = &current_panel->dir;
1501 char *name = NULL;
1503 for (i = 0, entry = find_list->list; entry != NULL; i++, entry = g_list_next (entry))
1505 const char *lc_filename = NULL;
1506 WLEntry *le = (WLEntry *) entry->data;
1508 if ((le->text == NULL) || (le->data == NULL))
1509 continue;
1511 if (content_pattern != NULL)
1512 lc_filename = strchr (le->text + 4, ':') + 1;
1513 else
1514 lc_filename = le->text + 4;
1516 name = make_fullname (le->data, lc_filename);
1517 status = handle_path (list, name, &st, next_free, &link_to_dir, &stale_link);
1518 if (status == 0)
1520 g_free (name);
1521 continue;
1523 if (status == -1)
1525 g_free (name);
1526 break;
1529 /* don't add files more than once to the panel */
1530 if (content_pattern != NULL && next_free > 0
1531 && strcmp (list->list[next_free - 1].fname, name) == 0)
1533 g_free (name);
1534 continue;
1537 if (!next_free) /* first turn i.e clean old list */
1538 panel_clean_dir (current_panel);
1539 list->list[next_free].fnamelen = strlen (name);
1540 list->list[next_free].fname = name;
1541 list->list[next_free].f.marked = 0;
1542 list->list[next_free].f.link_to_dir = link_to_dir;
1543 list->list[next_free].f.stale_link = stale_link;
1544 list->list[next_free].f.dir_size_computed = 0;
1545 list->list[next_free].st = st;
1546 list->list[next_free].sort_key = NULL;
1547 list->list[next_free].second_sort_key = NULL;
1548 next_free++;
1549 if (!(next_free & 15))
1550 rotate_dash ();
1553 if (next_free)
1555 current_panel->count = next_free;
1556 current_panel->is_panelized = 1;
1558 if (start_dir[0] == PATH_SEP)
1560 int ret;
1561 strcpy (current_panel->cwd, PATH_SEP_STR);
1562 ret = chdir (PATH_SEP_STR);
1567 g_free (content_pattern);
1568 kill_gui ();
1569 do_search (NULL); /* force do_search to release resources */
1570 g_free (old_dir);
1571 old_dir = NULL;
1573 return return_value;
1576 /* --------------------------------------------------------------------------------------------- */
1577 /*** public functions ****************************************************************************/
1578 /* --------------------------------------------------------------------------------------------- */
1580 void
1581 do_find (void)
1583 char *start_dir = NULL, *pattern = NULL, *content = NULL;
1584 char *filename = NULL, *dirname = NULL;
1585 int v;
1586 gboolean dir_and_file_set;
1588 while (find_parameters (&start_dir, &pattern, &content))
1590 if (pattern[0] == '\0')
1591 break; /* nothing search */
1593 dirname = filename = NULL;
1594 is_start = FALSE;
1595 v = find_file (start_dir, pattern, content, &dirname, &filename);
1596 g_free (pattern);
1598 if (v == B_ENTER)
1600 if (dirname != NULL)
1602 do_cd (dirname, cd_exact);
1603 if (filename != NULL)
1604 try_to_select (current_panel,
1605 filename + (content != NULL
1606 ? strchr (filename + 4, ':') - filename + 1 : 4));
1608 else if (filename != NULL)
1609 do_cd (filename, cd_exact);
1611 g_free (dirname);
1612 g_free (filename);
1613 break;
1616 g_free (content);
1617 dir_and_file_set = (dirname != NULL) && (filename != NULL);
1618 g_free (dirname);
1619 g_free (filename);
1621 if (v == B_CANCEL)
1622 break;
1624 if (v == B_PANELIZE)
1626 if (dir_and_file_set)
1628 try_to_select (current_panel, NULL);
1629 panel_re_sort (current_panel);
1630 try_to_select (current_panel, NULL);
1632 break;
1637 /* --------------------------------------------------------------------------------------------- */