Merge remote branch 'osp/only-directories'
[midnight-commander/osp/rehorto2.git] / src / find.c.orig
blob14a700b3bae054192a810670d853f2a433802ef6
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 rewrote.
7    
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.
12    
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
24  */
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/vfs/mc-vfs/vfs.h"
43 #include "lib/strutil.h"
45 #include "setup.h"              /* verbose */
46 #include "dialog.h"
47 #include "widget.h"
48 #include "dir.h"
49 #include "panel.h"              /* current_panel */
50 #include "main.h"               /* do_cd, try_to_select */
51 #include "wtools.h"
52 #include "cmd.h"                /* view_file_at_line */
53 #include "boxes.h"
54 #include "history.h"            /* MC_HISTORY_SHARED_SEARCH */
55 #include "layout.h"             /* mc_refresh() */
57 #include "find.h"
59 /* Size of the find parameters window */
60 #if HAVE_CHARSET
61 static int FIND_Y = 16;
62 #else
63 static int FIND_Y = 15;
64 #endif
65 static int FIND_X = 68;
67 /* Size of the find window */
68 #define FIND2_Y (LINES - 4)
70 static int FIND2_X = 64;
71 #define FIND2_X_USE (FIND2_X - 20)
73 /* A couple of extra messages we need */
74 enum {
75     B_STOP = B_USER + 1,
76     B_AGAIN,
77     B_PANELIZE,
78     B_TREE,
79     B_VIEW
82 typedef enum {
83     FIND_CONT = 0,
84     FIND_SUSPEND,
85     FIND_ABORT
86 } FindProgressStatus;
88 /* List of directories to be ignored, separated by ':' */
89 <<<<<<< HEAD
90 char *find_ignore_dirs = NULL;
92 /* static variables to remember find parameters */
93 static WInput *in_start;                        /* Start path */
94 static WInput *in_name;                         /* Filename */
95 static WInput *in_with;                         /* Text inside filename */
96 static WCheck *file_case_sens_cbox;             /* "case sensitive" checkbox */
97 static WCheck *file_pattern_cbox;               /* File name is glob or regexp */
98 static WCheck *recursively_cbox;
99 static WCheck *skip_hidden_cbox;
100 static WCheck *content_case_sens_cbox;          /* "case sensitive" checkbox */
101 static WCheck *content_regexp_cbox;             /* "find regular expression" checkbox */
102 static WCheck *content_first_hit_cbox;          /* "First hit" checkbox" */
103 static WCheck *content_whole_words_cbox;        /* "whole words" checkbox */
104 #ifdef HAVE_CHARSET
105 static WCheck *file_all_charsets_cbox;
106 static WCheck *content_all_charsets_cbox;
107 #endif
109 static gboolean running = FALSE;        /* nice flag */
110 static char *find_pattern = NULL;       /* Pattern to search */
111 static char *content_pattern = NULL;    /* pattern to search inside files; if
112                                            content_regexp_flag is true, it contains the
113                                            regex pattern, else the search string. */
114 static unsigned long matches;           /* Number of matches */
115 static gboolean is_start = FALSE;       /* Status of the start/stop toggle button */
116 static char *old_dir = NULL;
117 =======
118 char *find_ignore_dirs = 0;
120 static WInput *in_start;        /* Start path */
121 static WInput *in_name;         /* Pattern to search */
122 static WInput *in_with;         /* Text inside filename */
123 static WCheck *case_sense;      /* "case sensitive" checkbox */
124 static WCheck *find_regex_cbox; /* [x] find regular expression */
125 static WCheck *only_dirs_cbox;  /* [x] Only directories */
127 static int running = 0;         /* nice flag */
128 static char *find_pattern;      /* Pattern to search */
129 static char *content_pattern;   /* pattern to search inside files; if
130                                    find_regex_flag is true, it contains the
131                                    regex pattern, else the search string. */
132 static int count;               /* Number of files displayed */
133 static int matches;             /* Number of matches */
134 static int is_start;            /* Status of the start/stop toggle button */
135 static char *old_dir;
136 >>>>>>> osp/only-directories
138 /* Where did we stop */
139 static int resuming;
140 static int last_line;
141 static int last_pos;
143 static Dlg_head *find_dlg;      /* The dialog */
144 static WButton *stop_button;    /* pointer to the stop button */
145 static WLabel *status_label;    /* Finished, Searching etc. */
146 static WLabel *found_num_label; /* Number of found items */
147 static WListbox *find_list;     /* Listbox with the file list */
149 /* This keeps track of the directory stack */
150 #if GLIB_CHECK_VERSION (2, 14, 0)
151 static GQueue dir_queue = G_QUEUE_INIT;
152 #else
153 typedef struct dir_stack {
154     char *name;
155     struct dir_stack *prev;
156 } dir_stack;
158 static dir_stack *dir_stack_base = 0;
159 #endif                           /* GLIB_CHECK_VERSION */
161 static struct {
162         const char* text;
163         int len;        /* length including space and brackets */
164         int x;
165 } fbuts [] = {
166         { N_("&Suspend"),   11, 29 },
167         { N_("Con&tinue"),  12, 29 },
168         { N_("&Chdir"),     11, 3  },
169         { N_("&Again"),     9,  17 },
170         { N_("&Quit"),      8,  43 },
171         { N_("Pane&lize"),  12, 3  },
172         { N_("&View - F3"), 13, 20 },
173         { N_("&Edit - F4"), 13, 38 }
176 /* find file options */
177 typedef struct
179     /* file name options */
180     gboolean file_case_sens;
181     gboolean file_pattern;
182     gboolean find_recurs;
183     gboolean skip_hidden;
184     gboolean file_all_charsets;
186     /* file content options */
187     gboolean content_case_sens;
188     gboolean content_regexp;
189     gboolean content_first_hit;
190     gboolean content_whole_words;
191     gboolean content_all_charsets;
192 } find_file_options_t;
194 static find_file_options_t options =
196     TRUE, TRUE, TRUE, FALSE, FALSE,
197     TRUE, FALSE, FALSE, FALSE, FALSE
200 static char *in_start_dir = INPUT_LAST_TEXT;
202 static mc_search_t *search_file_handle = NULL;
203 static mc_search_t *search_content_handle = NULL;
205 static void
206 find_load_options (void)
208     static gboolean loaded = FALSE;
209     char *ignore_dirs;
211     if (loaded)
212         return;
214     loaded = TRUE;
216     /* Back compatibility: try load old parameter at first */
217     ignore_dirs = mc_config_get_string (mc_main_config, "Misc", "find_ignore_dirs", "");
218     if (ignore_dirs [0] != '\0') {
219         find_ignore_dirs = g_strconcat (":", ignore_dirs, ":", (char *) NULL);
220         mc_config_set_string (mc_main_config, "FindFile", "ignore_dirs", ignore_dirs);
221     }
222     g_free (ignore_dirs);
223     mc_config_del_param (mc_main_config, "Misc", "find_ignore_dirs");
225     /* Then load new parameters */
226     ignore_dirs = mc_config_get_string (mc_main_config, "FindFile", "ignore_dirs", "");
227     if (ignore_dirs [0] != '\0') {
228         g_free (find_ignore_dirs);
229         find_ignore_dirs = g_strconcat (":", ignore_dirs, ":", (char *) NULL);
230     }
231     g_free (ignore_dirs);
233     options.file_case_sens = mc_config_get_bool (mc_main_config, "FindFile", "file_case_sens", TRUE);
234     options.file_pattern = mc_config_get_bool (mc_main_config, "FindFile", "file_shell_pattern", TRUE);
235     options.find_recurs = mc_config_get_bool (mc_main_config, "FindFile", "file_find_recurs", TRUE);
236     options.skip_hidden = mc_config_get_bool (mc_main_config, "FindFile", "file_skip_hidden", FALSE);
237     options.file_all_charsets = mc_config_get_bool (mc_main_config, "FindFile", "file_all_charsets", FALSE);
238     options.content_case_sens = mc_config_get_bool (mc_main_config, "FindFile", "content_case_sens", TRUE);
239     options.content_regexp = mc_config_get_bool (mc_main_config, "FindFile", "content_regexp", FALSE);
240     options.content_first_hit = mc_config_get_bool (mc_main_config, "FindFile", "content_first_hit", FALSE);
241     options.content_whole_words = mc_config_get_bool (mc_main_config, "FindFile", "content_whole_words", FALSE);
242     options.content_all_charsets = mc_config_get_bool (mc_main_config, "FindFile", "content_all_charsets", FALSE);
245 static void
246 find_save_options (void)
248     mc_config_set_bool (mc_main_config, "FindFile", "file_case_sens", options.file_case_sens);
249     mc_config_set_bool (mc_main_config, "FindFile", "file_shell_pattern", options.file_pattern);
250     mc_config_set_bool (mc_main_config, "FindFile", "file_find_recurs", options.find_recurs);
251     mc_config_set_bool (mc_main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
252     mc_config_set_bool (mc_main_config, "FindFile", "file_all_charsets", options.file_all_charsets);
253     mc_config_set_bool (mc_main_config, "FindFile", "content_case_sens", options.content_case_sens);
254     mc_config_set_bool (mc_main_config, "FindFile", "content_regexp", options.content_regexp);
255     mc_config_set_bool (mc_main_config, "FindFile", "content_first_hit", options.content_first_hit);
256     mc_config_set_bool (mc_main_config, "FindFile", "content_whole_words", options.content_whole_words);
257     mc_config_set_bool (mc_main_config, "FindFile", "content_all_charsets", options.content_all_charsets);
260 static inline char *
261 add_to_list (const char *text, void *data)
263     return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data);
266 static inline void
267 stop_idle (void *data)
269     set_idle_proc (data, 0);
272 static inline void
273 status_update (const char *text)
275     label_set_text (status_label, text);
278 static void
279 found_num_update (void)
281     char buffer [BUF_TINY];
282     g_snprintf (buffer, sizeof (buffer), _("Found: %ld"), matches);
283     label_set_text (found_num_label, buffer);
286 <<<<<<< HEAD
287 static void
288 get_list_info (char **file, char **dir)
290     listbox_get_current (find_list, file, (void **) dir);
293 /* check regular expression */
294 static gboolean
295 find_check_regexp (const char *r)
297     mc_search_t *search;
298     gboolean regexp_ok = FALSE;
300     search = mc_search_new (r, -1);
302     if (search != NULL) {
303         search->search_type = MC_SEARCH_T_REGEX;
304         regexp_ok = mc_search_prepare (search);
305         mc_search_free (search);
306     }
308     return regexp_ok;
310 =======
311 /* FIXME: r should be local variable */
312 static regex_t *r; /* Pointer to compiled content_pattern */
314 static int case_sensitive = 1;
315 static gboolean find_regex_flag = TRUE;
316 static gboolean only_dirs_flag = FALSE;
317 static int find_recursively = 1;
318 >>>>>>> osp/only-directories
321  * Callback for the parameter dialog.
322  * Validate regex, prevent closing the dialog if it's invalid.
323  */
324 static cb_ret_t
325 find_parm_callback (Dlg_head *h, Widget *sender,
326                     dlg_msg_t msg, int parm, void *data)
328     switch (msg) {
329     case DLG_VALIDATE:
330         if (h->ret_value != B_ENTER)
331             return MSG_HANDLED;
333         /* check filename regexp */
334         if (!(file_pattern_cbox->state & C_BOOL)
335             && (in_name->buffer[0] != '\0')
336             && !find_check_regexp (in_name->buffer)) {
337                 message (D_ERROR, MSG_ERROR, _(" Malformed regular expression "));
338                 dlg_select_widget (in_name);
339                 h->running = 1;         /* Don't stop the dialog */
340                 return MSG_HANDLED;
341         }
343         /* check content regexp */
344         if ((content_regexp_cbox->state & C_BOOL)
345             && (in_with->buffer[0] != '\0')
346             && !find_check_regexp (in_with->buffer)) {
347                 message (D_ERROR, MSG_ERROR, _(" Malformed regular expression "));
348                 dlg_select_widget (in_with);
349                 h->running = 1;         /* Don't stop the dialog */
350                 return MSG_HANDLED;
351         }
353         return MSG_HANDLED;
355     default:
356         return default_dlg_callback (h, sender, msg, parm, data);
357     }
361  * find_parameters: gets information from the user
363  * If the return value is TRUE, then the following holds:
365  * START_DIR and PATTERN are pointers to char * and upon return they
366  * contain the information provided by the user.
368  * CONTENT holds a strdup of the contents specified by the user if he
369  * asked for them or 0 if not (note, this is different from the
370  * behavior for the other two parameters.
372  */
373 static gboolean
374 find_parameters (char **start_dir, char **pattern, char **content)
376     gboolean return_value;
378     /* file name */
379     const char *file_case_label = N_("Cas&e sensitive");
380     const char *file_pattern_label = N_("&Using shell patterns");
381     const char *file_recurs_label = N_("&Find recursively");
382     const char *file_skip_hidden_label = N_("S&kip hidden");
383 #ifdef HAVE_CHARSET
384     const char *file_all_charsets_label = N_("&All charsets");
385 #endif
387     /* file content */
388     const char *content_case_label = N_("Case sens&itive");
389     const char *content_regexp_label = N_("Re&gular expression");
390     const char *content_first_hit_label = N_("Fir&st hit");
391     const char *content_whole_words_label = N_("&Whole words");
392 #ifdef HAVE_CHARSET
393     const char *content_all_charsets_label = N_("All cha&rsets");
394 #endif
396     const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
398     int b0, b1, b2;
400 #ifdef ENABLE_NLS
401     {
402         int i = sizeof (buts) / sizeof (buts[0]);
403         while (i-- != 0)
404             buts[i] = _(buts[i]);
406         file_case_label = _(file_case_label);
407         file_pattern_label = _(file_pattern_label);
408         file_recurs_label = _(file_recurs_label);
409         file_skip_hidden_label = _(file_skip_hidden_label);
410 #ifdef HAVE_CHARSET
411         file_all_charsets_label = _(file_all_charsets_label);
412         content_all_charsets_label = _(content_all_charsets_label);
413 #endif
414         content_case_label = _(content_case_label);
415         content_regexp_label = _(content_regexp_label);
416         content_first_hit_label = _(content_first_hit_label);
417         content_whole_words_label = _(content_whole_words_label);
418     }
419 #endif                          /* ENABLE_NLS */
421     b0 = str_term_width1 (buts[0]) + 6; /* default button */
422     b1 = str_term_width1 (buts[1]) + 4;
423     b2 = str_term_width1 (buts[2]) + 4;
425     find_load_options ();
427     if (in_start_dir == NULL)
428         in_start_dir = g_strdup (".");
430 find_par_start:
431     find_dlg =
432         create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
433                     find_parm_callback, "[Find File]", _("Find File"),
434                     DLG_CENTER | DLG_REVERSE);
436     add_widget (find_dlg,
437                 button_new (FIND_Y - 3, FIND_X * 3/4 - b1/2, B_CANCEL, NORMAL_BUTTON, buts[1], 0));
438     add_widget (find_dlg,
439                 button_new (FIND_Y - 3, FIND_X/4 - b0/2, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
441 <<<<<<< HEAD
442 #ifdef HAVE_CHARSET
443     content_all_charsets_cbox = check_new (11, FIND_X / 2 + 1,
444                 options.content_all_charsets, content_all_charsets_label);
445     add_widget (find_dlg, content_all_charsets_cbox);
446 #endif
447 =======
448     recursively_cbox =
449         check_new (6, istart, find_recursively, recurs_label);
450     only_dirs_cbox =
451         check_new (7, istart, only_dirs_flag, _("Only &directories"));
453     find_regex_cbox = check_new (10, istart, find_regex_flag, _("&Regular expression"));
454     add_widget (find_dlg, find_regex_cbox);
455 >>>>>>> osp/only-directories
457     content_whole_words_cbox = check_new (10, FIND_X / 2 + 1, options.content_whole_words, content_whole_words_label);
458     add_widget (find_dlg, content_whole_words_cbox);
460     content_first_hit_cbox = check_new (9, FIND_X / 2 + 1, options.content_first_hit, content_first_hit_label);
461     add_widget (find_dlg, content_first_hit_cbox);
463     content_regexp_cbox = check_new (8, FIND_X / 2 + 1, options.content_regexp, content_regexp_label);
464     add_widget (find_dlg, content_regexp_cbox);
466     content_case_sens_cbox = check_new (7, FIND_X / 2 + 1, options.content_case_sens, content_case_label);
467     add_widget (find_dlg, content_case_sens_cbox);
469 #ifdef HAVE_CHARSET
470     file_all_charsets_cbox = check_new (11, 3,
471                 options.file_all_charsets, file_all_charsets_label);
472     add_widget (find_dlg, file_all_charsets_cbox);
473 #endif
475 <<<<<<< HEAD
476 <<<<<<< HEAD
477     skip_hidden_cbox = check_new (10, 3, options.skip_hidden, file_skip_hidden_label);
478     add_widget (find_dlg, skip_hidden_cbox);
480     recursively_cbox = check_new (9, 3, options.find_recurs, file_recurs_label);
481 =======
482     add_widget (find_dlg, only_dirs_cbox);
483 >>>>>>> osp/only-directories
484 =======
485     add_widget (find_dlg, only_dirs_cbox);
486 >>>>>>> osp/only-directories
487     add_widget (find_dlg, recursively_cbox);
489     file_pattern_cbox = check_new (8, 3, options.file_pattern, file_pattern_label);
490     add_widget (find_dlg, file_pattern_cbox);
492     file_case_sens_cbox = check_new (7, 3, options.file_case_sens, file_case_label);
493     add_widget (find_dlg, file_case_sens_cbox);
495     in_with = input_new (6, FIND_X / 2 + 1, INPUT_COLOR, FIND_X / 2 - 4, INPUT_LAST_TEXT,
496                          MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_DEFAULT);
497     add_widget (find_dlg, in_with);
498     add_widget (find_dlg, label_new (5, FIND_X / 2 + 1, _("Content:")));
500     in_name = input_new (6, 3, INPUT_COLOR, FIND_X / 2 - 4, INPUT_LAST_TEXT, "name",
501                          INPUT_COMPLETE_DEFAULT);
502     add_widget (find_dlg, in_name);
503     add_widget (find_dlg, label_new (5, 3, _("File name:")));
505     add_widget (find_dlg,
506                 button_new (3, FIND_X - b2 - 2, B_TREE, NORMAL_BUTTON, buts[2], 0));
508     in_start = input_new (3, 3, INPUT_COLOR, FIND_X - b2 - 6, in_start_dir, "start",
509                           INPUT_COMPLETE_DEFAULT);
510     add_widget (find_dlg, in_start);
511     add_widget (find_dlg, label_new (2, 3, _("Start at:")));
513     dlg_select_widget (in_name);
515     switch (run_dlg (find_dlg)) {
516     case B_CANCEL:
517         return_value = FALSE;
518         break;
520     case B_TREE:
521 <<<<<<< HEAD
522     {
523         char temp_dir[MC_MAXPATHLEN];
525         g_strlcpy (temp_dir, in_start->buffer, sizeof (temp_dir));
526 #ifdef HAVE_CHARSET
527         options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
528         options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
529 #endif
530         options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
531         options.content_regexp = content_regexp_cbox->state & C_BOOL;
532         options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
533         options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
534         options.file_pattern = file_pattern_cbox->state & C_BOOL;
535         options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
536         options.find_recurs = recursively_cbox->state & C_BOOL;
537         options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
538 =======
539         temp_dir = g_strdup (in_start->buffer);
540         case_sensitive = case_sense->state & C_BOOL;
541         find_regex_flag = find_regex_cbox->state & C_BOOL;
542         find_recursively = recursively_cbox->state & C_BOOL;
543         only_dirs_flag = only_dirs_cbox->state & C_BOOL;
544 <<<<<<< HEAD
545 >>>>>>> osp/only-directories
546 =======
547 >>>>>>> osp/only-directories
548         destroy_dlg (find_dlg);
550         if ((temp_dir[0] == '\0')
551                 || ((temp_dir[0] == '.') && (temp_dir[1] == '\0')))
552             g_strlcpy (temp_dir, current_panel->cwd, sizeof (temp_dir));
554         if (in_start_dir != INPUT_LAST_TEXT)
555             g_free (in_start_dir);
556         in_start_dir = tree_box (temp_dir);
557         if (in_start_dir == NULL)
558             in_start_dir = g_strdup (temp_dir);
559         /* Warning: Dreadful goto */
560         goto find_par_start;
561         break;
562     }
564     default:
565 <<<<<<< HEAD
566 #ifdef HAVE_CHARSET
567         options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
568         options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
569 #endif
570         options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
571         options.content_regexp = content_regexp_cbox->state & C_BOOL;
572         options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
573         options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
574         options.find_recurs = recursively_cbox->state & C_BOOL;
575         options.file_pattern = file_pattern_cbox->state & C_BOOL;
576         options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
577         options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
579         *content = (in_with->buffer[0] != '\0') ? g_strdup (in_with->buffer) : NULL;
580         *start_dir = g_strdup ((in_start->buffer[0] != '\0') ? in_start->buffer : ".");
581 =======
582         g_free (in_contents);
583         if (in_with->buffer[0]) {
584             *content = g_strdup (in_with->buffer);
585             in_contents = g_strdup (*content);
586         } else {
587             *content = in_contents = NULL;
588             r = 0;
589         }
591         case_sensitive = case_sense->state & C_BOOL;
592         find_regex_flag = find_regex_cbox->state & C_BOOL;
593         find_recursively = recursively_cbox->state & C_BOOL;
594         only_dirs_flag = only_dirs_cbox->state & C_BOOL;
595         return_value = 1;
596         *start_dir = g_strdup (in_start->buffer);
597 >>>>>>> osp/only-directories
598         *pattern = g_strdup (in_name->buffer);
599         if (in_start_dir != INPUT_LAST_TEXT)
600             g_free (in_start_dir);
601         in_start_dir = g_strdup (*start_dir);
603         find_save_options ();
605         return_value = TRUE;
606     }
608     destroy_dlg (find_dlg);
610     return return_value;
613 #if GLIB_CHECK_VERSION (2, 14, 0)
615 static inline void
616 push_directory (const char *dir)
618     g_queue_push_head (&dir_queue, (void *) dir);
621 static inline char *
622 pop_directory (void)
624     return (char *) g_queue_pop_tail (&dir_queue);
627 /* Remove all the items in the stack */
628 static void
629 clear_stack (void)
631     g_queue_foreach (&dir_queue, (GFunc) g_free, NULL);
632     g_queue_clear (&dir_queue);
635 #else                           /* GLIB_CHAECK_VERSION */
637 static void
638 push_directory (const char *dir)
640     dir_stack *new;
642     new = g_new (dir_stack, 1);
643     new->name = str_unconst (dir);
644     new->prev = dir_stack_base;
645     dir_stack_base = new;
648 static char *
649 pop_directory (void)
651     char *name = NULL;
653     if (dir_stack_base != NULL) {
654         dir_stack *next;
655         name = dir_stack_base->name;
656         next = dir_stack_base->prev;
657         g_free (dir_stack_base);
658         dir_stack_base = next;
659     }
661     return name;
664 /* Remove all the items in the stack */
665 static void
666 clear_stack (void)
668     char *dir = NULL;
669     while ((dir = pop_directory ()) != NULL)
670         g_free (dir);
673 #endif                          /* GLIB_CHAECK_VERSION */
675 static void
676 insert_file (const char *dir, const char *file)
678     char *tmp_name = NULL;
679     static char *dirname = NULL;
681     while (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
682         dir++;
684     if (old_dir){
685         if (strcmp (old_dir, dir)){
686             g_free (old_dir);
687             old_dir = g_strdup (dir);
688             dirname = add_to_list (dir, NULL);
689         }
690     } else {
691         old_dir = g_strdup (dir);
692         dirname = add_to_list (dir, NULL);
693     }
695     tmp_name = g_strdup_printf ("    %s", file);
696     add_to_list (tmp_name, dirname);
697     g_free (tmp_name);
700 static void
701 find_add_match (const char *dir, const char *file)
703     insert_file (dir, file);
705     /* Don't scroll */
706     if (matches == 0)
707         listbox_select_first (find_list);
708     send_message (&find_list->widget, WIDGET_DRAW, 0);
710     matches++;
711     found_num_update ();
715  * get_line_at:
717  * Returns malloced null-terminated line from file file_fd.
718  * Input is buffered in buf_size long buffer.
719  * Current pos in buf is stored in pos.
720  * n_read - number of read chars.
721  * has_newline - is there newline ?
722  */
723 static char *
724 get_line_at (int file_fd, char *buf, int buf_size, int *pos, int *n_read,
725              gboolean *has_newline)
727     char *buffer = NULL;
728     int buffer_size = 0;
729     char ch = 0;
730     int i = 0;
732     for (;;) {
733         if (*pos >= *n_read) {
734             *pos = 0;
735             *n_read = mc_read (file_fd, buf, buf_size);
736             if (*n_read <= 0)
737                 break;
738         }
740         ch = buf[(*pos)++];
741         if (ch == '\0') {
742             /* skip possible leading zero(s) */
743             if (i == 0)
744                 continue;
745             else
746                 break;
747         }
749         if (i >= buffer_size - 1) {
750             buffer = g_realloc (buffer, buffer_size += 80);
751         }
752         /* Strip newline */
753         if (ch == '\n')
754             break;
756         buffer[i++] = ch;
757     }
759     *has_newline = (ch != '\0');
761     if (buffer != NULL)
762         buffer[i] = '\0';
764     return buffer;
767 static FindProgressStatus
768 check_find_events(Dlg_head *h)
770     Gpm_Event event;
771     int c;
773     event.x = -1;
774     c = tty_get_event (&event, h->mouse_status == MOU_REPEAT, FALSE);
775     if (c != EV_NONE) {
776         dlg_process_event (h, c, &event);
777         if (h->ret_value == B_ENTER
778             || h->ret_value == B_CANCEL
779             || h->ret_value == B_AGAIN
780             || h->ret_value == B_PANELIZE) {
781             /* dialog terminated */
782             return FIND_ABORT;
783         }
784         if (!(h->flags & DLG_WANT_IDLE)) {
785             /* searching suspended */
786             return FIND_SUSPEND;
787         }
788     }
790     return FIND_CONT;
794  * search_content:
796  * Search the content_pattern string in the DIRECTORY/FILE.
797  * It will add the found entries to the find listbox.
799  * returns FALSE if do_search should look for another file
800  *         TRUE if do_search should exit and proceed to the event handler
801  */
802 static gboolean
803 search_content (Dlg_head *h, const char *directory, const char *filename)
805     struct stat s;
806     char buffer [BUF_4K];
807     char *fname = NULL;
808     int file_fd;
809     gboolean ret_val = FALSE;
811     fname = concat_dir_and_file (directory, filename);
813     if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode)){
814         g_free (fname);
815         return 0;
816     }
818     file_fd = mc_open (fname, O_RDONLY);
819     g_free (fname);
821     if (file_fd == -1)
822         return 0;
824     g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), str_trunc (filename, FIND2_X_USE));
826     status_update (buffer);
827     mc_refresh ();
829     tty_enable_interrupt_key ();
830     tty_got_interrupt ();
832     {
833         int line = 1;
834         int pos = 0;
835         int n_read = 0;
836         gboolean has_newline;
837         char *p = NULL;
838         gboolean found = FALSE;
839         gsize found_len;
840         char result [BUF_MEDIUM];
842         if (resuming) {
843             /* We've been previously suspended, start from the previous position */
844             resuming = 0;
845             line = last_line;
846             pos = last_pos;
847         }
848         while (!ret_val
849                 && (p = get_line_at (file_fd, buffer, sizeof (buffer),
850                                         &pos, &n_read, &has_newline)) != NULL) {
851             if (!found          /* Search in binary line once */
852                     && mc_search_run (search_content_handle,
853                                         (const void *) p, 0, strlen (p), &found_len)) {
854                 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
855                 find_add_match (directory, result);
856                 found = TRUE;
857             }
858             g_free (p);
860             if (found && options.content_first_hit)
861                 break;
863             if (has_newline) {
864                 found = FALSE;
865                 line++;
866             }
868             if ((line & 0xff) == 0) {
869                 FindProgressStatus res;
870                 res = check_find_events(h);
871                 switch (res) {
872                 case FIND_ABORT:
873                     stop_idle (h);
874                     ret_val = TRUE;
875                     break;
876                 case FIND_SUSPEND:
877                     resuming = 1;
878                     last_line = line;
879                     last_pos = pos;
880                     ret_val = TRUE;
881                     break;
882                 default:
883                     break;
884                 }
885             }
887         }
888     }
889     tty_disable_interrupt_key ();
890     mc_close (file_fd);
891     return ret_val;
894 static int
895 do_search (struct Dlg_head *h)
897     static struct dirent *dp = NULL;
898     static DIR  *dirp = NULL;
899     static char *directory = NULL;
900     struct stat tmp_stat;
901     static int pos = 0;
902     static int subdirs_left = 0;
903     gsize bytes_found;
904     unsigned long count;                        /* Number of files displayed */
906     if (!h) { /* someone forces me to close dirp */
907         if (dirp) {
908             mc_closedir (dirp);
909             dirp = NULL;
910         }
911         g_free (directory);
912         directory = NULL;
913         dp = NULL;
914         return 1;
915     }
917     search_content_handle = mc_search_new(content_pattern, -1);
918     if (search_content_handle) {
919         search_content_handle->search_type = options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
920         search_content_handle->is_case_sentitive = options.content_case_sens;
921         search_content_handle->whole_words = options.content_whole_words;
922         search_content_handle->is_all_charsets = options.content_all_charsets;
923     }
924     search_file_handle = mc_search_new(find_pattern, -1);
925     search_file_handle->search_type = options.file_pattern ?  MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
926     search_file_handle->is_case_sentitive = options.file_case_sens;
927     search_file_handle->is_all_charsets = options.file_all_charsets;
928     search_file_handle->is_entire_line = options.file_pattern;
930     count = 0;
932  do_search_begin:
933     while (!dp){
934         if (dirp){
935             mc_closedir (dirp);
936             dirp = 0;
937         }
938         
939         while (!dirp){
940             char *tmp = NULL;
942             tty_setcolor (REVERSE_COLOR);
943             while (1) {
944                 char *temp_dir = NULL;
945                 gboolean found;
947                 tmp = pop_directory ();
948                 if (tmp == NULL) {
949                     running = FALSE;
950                     status_update (_("Finished"));
951                     stop_idle (h);
952                     mc_search_free (search_file_handle);
953                     search_file_handle = NULL;
954                     mc_search_free (search_content_handle);
955                     search_content_handle = NULL;
956                     return 0;
957                 }
959                 if ((find_ignore_dirs == NULL) || (find_ignore_dirs[0] == '\0'))
960                     break;
962                 temp_dir = g_strdup_printf (":%s:", tmp);
963                 found = strstr (find_ignore_dirs, temp_dir) != 0;
964                 g_free (temp_dir);
965                 
966                 if (!found)
967                     break;
969                 g_free (tmp);
970             }
972             g_free (directory);
973             directory = tmp;
975             if (verbose){
976                 char buffer [BUF_SMALL];
978                 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
979                             str_trunc (directory, FIND2_X_USE));
980                 status_update (buffer);
981             }
982             /* mc_stat should not be called after mc_opendir
983                because vfs_s_opendir modifies the st_nlink
984             */
985             if (!mc_stat (directory, &tmp_stat))
986                 subdirs_left = tmp_stat.st_nlink - 2;
987             else
988                 subdirs_left = 0;
990             dirp = mc_opendir (directory);
991         }   /* while (!dirp) */
993         /* skip invalid filenames */
994         while ((dp = mc_readdir (dirp)) != NULL
995                  && !str_is_valid_string (dp->d_name))
996             ;
997     }   /* while (!dp) */
999     if (strcmp (dp->d_name, ".") == 0 ||
1000         strcmp (dp->d_name, "..") == 0){
1001         dp = mc_readdir (dirp);
1002         /* skip invalid filenames */
1003         while (dp != NULL && !str_is_valid_string (dp->d_name))
1004             dp = mc_readdir (dirp);
1006         mc_search_free(search_file_handle);
1007         search_file_handle = NULL;
1008         mc_search_free(search_content_handle);
1009         search_content_handle = NULL;
1010         return 1;
1011     }
1013 <<<<<<< HEAD
1014     if (!(options.skip_hidden && (dp->d_name[0] == '.'))) {
1015         gboolean search_ok;
1017         if ((subdirs_left != 0) && options.find_recurs
1018                 && (directory != NULL)) { /* Can directory be NULL ? */
1019             char *tmp_name = concat_dir_and_file (directory, dp->d_name);
1020             if (!mc_lstat (tmp_name, &tmp_stat)
1021                 && S_ISDIR (tmp_stat.st_mode)) {
1022                 push_directory (tmp_name);
1023                 subdirs_left--;
1024             } else
1025                 g_free (tmp_name);
1026         }
1028         search_ok = mc_search_run (search_file_handle, dp->d_name,
1029                                     0, strlen (dp->d_name), &bytes_found);
1031         if (search_ok) {
1032             if (content_pattern == NULL)
1033                 find_add_match (directory, dp->d_name);
1034             else if (search_content (h, directory, dp->d_name)) {
1035                 mc_search_free(search_file_handle);
1036                 search_file_handle = NULL;
1037                 mc_search_free(search_content_handle);
1038                 search_content_handle = NULL;
1039                 return 1;
1040             }
1041         }
1042     }
1044     /* skip invalid filenames */
1045     while ((dp = mc_readdir (dirp)) != NULL
1046             && !str_is_valid_string (dp->d_name))
1047         ;
1048 =======
1049     if (subdirs_left && find_recursively && directory) { /* Can directory be NULL ? */
1050         char *tmp_name = mhl_str_dir_plus_file (directory, dp->d_name);
1051         if (!mc_lstat (tmp_name, &tmp_stat)
1052             && S_ISDIR (tmp_stat.st_mode)) {
1053             push_directory (tmp_name);
1054             subdirs_left--;
1055             if (only_dirs_flag && regexp_match (find_pattern, dp->d_name, match_file)) {
1056                     find_add_match (h, directory, dp->d_name);
1057             }
1058         }
1059         g_free (tmp_name);
1060     }
1062     if (!only_dirs_flag && regexp_match (find_pattern, dp->d_name, match_file)){
1063         if (content_pattern) {
1064             if (search_content (h, directory, dp->d_name)) {
1065                 return 1;
1066             }
1067         } else 
1068             find_add_match (h, directory, dp->d_name);
1069     }
1070     
1071     dp = mc_readdir (dirp);
1072 >>>>>>> osp/only-directories
1074     /* Displays the nice dot */
1075     count++;
1076     if (!(count & 31)){
1077         /* For nice updating */
1078         const char rotating_dash[] = "|/-\\";
1080         if (verbose){
1081             pos = (pos + 1) % 4;
1082             tty_setcolor (DLG_NORMALC (h));
1083             dlg_move (h, FIND2_Y - 7, FIND2_X - 4);
1084             tty_print_char (rotating_dash [pos]);
1085             mc_refresh ();
1086         }
1087     } else
1088         goto do_search_begin;
1090     mc_search_free (search_file_handle);
1091     search_file_handle = NULL;
1092     mc_search_free (search_content_handle);
1093     search_content_handle = NULL;
1094     return 1;
1097 static void
1098 init_find_vars (void)
1100     g_free (old_dir);
1101     old_dir = NULL;
1102     matches = 0;
1104     /* Remove all the items in the stack */
1105     clear_stack ();
1108 static char *
1109 make_fullname (const char *dirname, const char *filename)
1112     if (strcmp(dirname, ".") == 0 || strcmp(dirname, "."PATH_SEP_STR) == 0)
1113         return g_strdup (filename);
1114     if (strncmp(dirname, "."PATH_SEP_STR, 2) == 0)
1115         return concat_dir_and_file (dirname + 2, filename);
1116     return concat_dir_and_file (dirname, filename);
1119 static void
1120 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
1122     char *fullname = NULL;
1123     const char *filename = NULL;
1124     int line;
1126     if (content_pattern != NULL) {
1127         filename = strchr (file + 4, ':') + 1;
1128         line = atoi (file + 4);
1129     } else {
1130         filename = file + 4;
1131         line = 0;
1132     }
1134     fullname = make_fullname (dir, filename);
1135     if (edit)
1136         do_edit_at_line (fullname, line);
1137     else
1138         view_file_at_line (fullname, unparsed_view, use_internal_view, line);
1139     g_free (fullname);
1142 static cb_ret_t
1143 view_edit_currently_selected_file (int unparsed_view, int edit)
1145     char *dir = NULL;
1146     char *text = NULL;
1148     listbox_get_current (find_list, &text, (void **) &dir);
1150     if ((text == NULL) || (dir == NULL))
1151         return MSG_NOT_HANDLED;
1153     find_do_view_edit (unparsed_view, edit, dir, text);
1154     return MSG_HANDLED;
1157 static cb_ret_t
1158 find_callback (struct Dlg_head *h, Widget *sender,
1159                 dlg_msg_t msg, int parm, void *data)
1161     switch (msg) {
1162     case DLG_KEY:
1163         if (parm == KEY_F (3) || parm == KEY_F (13)) {
1164             int unparsed_view = (parm == KEY_F (13));
1165             return view_edit_currently_selected_file (unparsed_view, 0);
1166         }
1167         if (parm == KEY_F (4)) {
1168             return view_edit_currently_selected_file (0, 1);
1169         }
1170         return MSG_NOT_HANDLED;
1172     case DLG_IDLE:
1173         do_search (h);
1174         return MSG_HANDLED;
1176     default:
1177         return default_dlg_callback (h, sender, msg, parm, data);
1178     }
1181 /* Handles the Stop/Start button in the find window */
1182 static int
1183 start_stop (int button)
1185     (void) button;
1187     running = is_start;
1188     set_idle_proc (find_dlg, running);
1189     is_start = !is_start;
1191     status_update (is_start ? _("Stopped") : _("Searching"));
1192     button_set_text (stop_button, fbuts [is_start ? 1 : 0].text);
1194     return 0;
1197 /* Handle view command, when invoked as a button */
1198 static int
1199 find_do_view_file (int button)
1201     (void) button;
1203     view_edit_currently_selected_file (0, 0);
1204     return 0;
1207 /* Handle edit command, when invoked as a button */
1208 static int
1209 find_do_edit_file (int button)
1211     (void) button;
1213     view_edit_currently_selected_file (0, 1);
1214     return 0;
1217 static void
1218 setup_gui (void)
1220 #ifdef ENABLE_NLS
1221     static gboolean i18n_flag = FALSE;
1223     if (!i18n_flag) {
1224         int i = sizeof (fbuts) / sizeof (fbuts[0]);
1225         while (i-- != 0) {
1226             fbuts[i].text = _(fbuts[i].text);
1227             fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1228         }
1230         fbuts[2].len += 2;      /* DEFPUSH_BUTTON */
1231         i18n_flag = TRUE;
1232     }
1233 #endif                          /* ENABLE_NLS */
1235     /*
1236      * Dynamically place buttons centered within current window size
1237      */
1238     {
1239         int l0 = max (fbuts[0].len, fbuts[1].len);
1240         int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
1241         int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
1242         int r1, r2;
1244         /* Check, if both button rows fit within FIND2_X */
1245         FIND2_X = max (l1 + 9, COLS - 16);
1246         FIND2_X = max (l2 + 8, FIND2_X);
1248         /* compute amount of space between buttons for each row */
1249         r1 = (FIND2_X - 4 - l1) % 5;
1250         l1 = (FIND2_X - 4 - l1) / 5;
1251         r2 = (FIND2_X - 4 - l2) % 4;
1252         l2 = (FIND2_X - 4 - l2) / 4;
1254         /* ...and finally, place buttons */
1255         fbuts[2].x = 2 + r1 / 2 + l1;
1256         fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
1257         fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
1258         fbuts[4].x = fbuts[0].x + l0 + l1;
1259         fbuts[5].x = 2 + r2 / 2 + l2;
1260         fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
1261         fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
1262     }
1264     find_dlg =
1265         create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
1266                     "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
1268     add_widget (find_dlg,
1269                 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
1270                             fbuts[7].text, find_do_edit_file));
1271     add_widget (find_dlg,
1272                 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
1273                             fbuts[6].text, find_do_view_file));
1274     add_widget (find_dlg,
1275                 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE,
1276                             NORMAL_BUTTON, fbuts[5].text, 0));
1278     add_widget (find_dlg,
1279                 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL,
1280                             NORMAL_BUTTON, fbuts[4].text, 0));
1281     stop_button =
1282         button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
1283                     fbuts[0].text, start_stop);
1284     add_widget (find_dlg, stop_button);
1285     add_widget (find_dlg,
1286                 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN,
1287                             NORMAL_BUTTON, fbuts[3].text, 0));
1288     add_widget (find_dlg,
1289                 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER,
1290                             DEFPUSH_BUTTON, fbuts[2].text, 0));
1292     status_label = label_new (FIND2_Y - 7, 4, _("Searching"));
1293     add_widget (find_dlg, status_label);
1295     found_num_label = label_new (FIND2_Y - 6, 4, "");
1296     add_widget (find_dlg, found_num_label);
1298     find_list =
1299         listbox_new (2, 2, FIND2_Y - 10, FIND2_X - 4, FALSE, NULL);
1300     add_widget (find_dlg, find_list);
1303 static int
1304 run_process (void)
1306     resuming = 0;
1307     set_idle_proc (find_dlg, 1);
1308     return run_dlg (find_dlg);
1311 static void
1312 kill_gui (void)
1314     set_idle_proc (find_dlg, 0);
1315     destroy_dlg (find_dlg);
1318 static int
1319 find_file (const char *start_dir, const char *pattern, const char *content,
1320             char **dirname, char **filename)
1322     int return_value = 0;
1323     char *dir_tmp = NULL, *file_tmp = NULL;
1325     setup_gui ();
1327     /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1328     find_pattern = str_unconst (pattern);
1329     content_pattern = (content != NULL && str_is_valid_string (content)) 
1330             ? g_strdup(content)
1331             : NULL;
1333     init_find_vars ();
1334     push_directory (start_dir);
1336     return_value = run_process ();
1338     /* Remove all the items in the stack */
1339     clear_stack ();
1341     get_list_info (&file_tmp, &dir_tmp);
1343     if (dir_tmp)
1344         *dirname = g_strdup (dir_tmp);
1345     if (file_tmp)
1346         *filename = g_strdup (file_tmp);
1348     if (return_value == B_PANELIZE && *filename) {
1349         int status, link_to_dir, stale_link;
1350         int next_free = 0;
1351         int i;
1352         struct stat st;
1353         GList *entry;
1354         dir_list *list = &current_panel->dir;
1355         char *name = NULL;
1357         for (i = 0, entry = find_list->list; entry != NULL;
1358                 i++, entry = g_list_next (entry)) {
1359             const char *lc_filename = NULL;
1360             WLEntry *le = (WLEntry *) entry->data;
1362             if ((le->text == NULL) || (le->data == NULL))
1363                 continue;
1365             if (content_pattern != NULL)
1366                 lc_filename = strchr (le->text + 4, ':') + 1;
1367             else
1368                 lc_filename = le->text + 4;
1370             name = make_fullname (le->data, lc_filename);
1371             status =
1372                 handle_path (list, name, &st, next_free, &link_to_dir,
1373                              &stale_link);
1374             if (status == 0) {
1375                 g_free (name);
1376                 continue;
1377             }
1378             if (status == -1) {
1379                 g_free (name);
1380                 break;
1381             }
1383             /* don't add files more than once to the panel */
1384             if (content_pattern != NULL && next_free > 0
1385                 && strcmp (list->list[next_free - 1].fname, name) == 0) {
1386                 g_free (name);
1387                 continue;
1388             }
1390             if (!next_free)     /* first turn i.e clean old list */
1391                 panel_clean_dir (current_panel);
1392             list->list[next_free].fnamelen = strlen (name);
1393             list->list[next_free].fname = name;
1394             list->list[next_free].f.marked = 0;
1395             list->list[next_free].f.link_to_dir = link_to_dir;
1396             list->list[next_free].f.stale_link = stale_link;
1397             list->list[next_free].f.dir_size_computed = 0;
1398             list->list[next_free].st = st;
1399             list->list[next_free].sort_key = NULL;
1400             list->list[next_free].second_sort_key = NULL;
1401             next_free++;
1402             if (!(next_free & 15))
1403                 rotate_dash ();
1404         }
1406         if (next_free) {
1407             current_panel->count = next_free;
1408             current_panel->is_panelized = 1;
1410             if (start_dir[0] == PATH_SEP) {
1411                 strcpy (current_panel->cwd, PATH_SEP_STR);
1412                 chdir (PATH_SEP_STR);
1413             }
1414         }
1415     }
1417     g_free (content_pattern);
1418     kill_gui ();
1419     do_search (NULL);           /* force do_search to release resources */
1420     g_free (old_dir);
1421     old_dir = NULL;
1423     return return_value;
1426 void
1427 do_find (void)
1429     char *start_dir = NULL, *pattern = NULL, *content = NULL;
1430     char *filename = NULL, *dirname = NULL;
1431     int  v;
1432     gboolean dir_and_file_set;
1434     while (find_parameters (&start_dir, &pattern, &content)){
1435         if (pattern [0] == '\0')
1436             break; /* nothing search*/
1438         dirname = filename = NULL;
1439         is_start = FALSE;
1440         v = find_file (start_dir, pattern, content, &dirname, &filename);
1441         g_free (pattern);
1443         if (v == B_ENTER){
1444             if (dirname || filename){
1445                 if (dirname){
1446                     do_cd (dirname, cd_exact);
1447                     if (filename)
1448                         try_to_select (current_panel, filename + (content ? 
1449                            (strchr (filename + 4, ':') - filename + 1) : 4) );
1450                 } else if (filename)
1451                     do_cd (filename, cd_exact);
1452                 select_item (current_panel);
1453             }
1454             g_free (dirname);
1455             g_free (filename);
1456             break;
1457         }
1459         g_free (content);
1460         dir_and_file_set = dirname && filename;
1461         g_free (dirname);
1462         g_free (filename);
1464         if (v == B_CANCEL)
1465             break;
1466         
1467         if (v == B_PANELIZE){
1468             if (dir_and_file_set){
1469                 try_to_select (current_panel, NULL);
1470                 panel_re_sort (current_panel);
1471                 try_to_select (current_panel, NULL);
1472             }
1473             break;
1474         }
1475     }