Revert "Try fix of compile warnings about assigned but unused variables"
[midnight-commander.git] / src / filemanager / find.c
blob0bea40b3b736cbfade8b9abb96f4b3d949e3d5b3
1 /*
2 Find file command for the Midnight Commander
4 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1995
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 /** \file find.c
28 * \brief Source: Find file command
31 #include <config.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <sys/stat.h>
40 #include "lib/global.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/key.h"
44 #include "lib/skin.h"
45 #include "lib/search.h"
46 #include "lib/mcconfig.h"
47 #include "lib/vfs/vfs.h"
48 #include "lib/strutil.h"
49 #include "lib/widget.h"
50 #include "lib/util.h" /* canonicalize_pathname() */
52 #include "src/setup.h" /* verbose */
53 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
54 #include "src/main.h" /* do_cd */
56 #include "dir.h"
57 #include "cmd.h" /* view_file_at_line */
58 #include "midnight.h" /* current_panel */
59 #include "boxes.h"
60 #include "panelize.h"
62 #include "find.h"
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 /* Size of the find window */
69 #define FIND2_Y (LINES - 4)
71 #define FIND2_X_USE (FIND2_X - 20)
73 /*** file scope type declarations ****************************************************************/
75 /* A couple of extra messages we need */
76 enum
78 B_STOP = B_USER + 1,
79 B_AGAIN,
80 B_PANELIZE,
81 B_TREE,
82 B_VIEW
85 typedef enum
87 FIND_CONT = 0,
88 FIND_SUSPEND,
89 FIND_ABORT
90 } FindProgressStatus;
92 /* find file options */
93 typedef struct
95 /* file name options */
96 gboolean file_case_sens;
97 gboolean file_pattern;
98 gboolean find_recurs;
99 gboolean skip_hidden;
100 gboolean file_all_charsets;
102 /* file content options */
103 gboolean content_use;
104 gboolean content_case_sens;
105 gboolean content_regexp;
106 gboolean content_first_hit;
107 gboolean content_whole_words;
108 gboolean content_all_charsets;
110 /* whether use ignore dirs or not */
111 gboolean ignore_dirs_enable;
112 /* list of directories to be ignored, separated by ':' */
113 char *ignore_dirs;
114 } find_file_options_t;
116 /*** file scope variables ************************************************************************/
118 /* Parsed ignore dirs */
119 static char **find_ignore_dirs = NULL;
121 /* Size of the find parameters window */
122 #ifdef HAVE_CHARSET
123 static int FIND_Y = 19;
124 #else
125 static int FIND_Y = 18;
126 #endif
127 static int FIND_X = 68;
129 static int FIND2_X = 64;
131 /* static variables to remember find parameters */
132 static WInput *in_start; /* Start path */
133 static WInput *in_name; /* Filename */
134 static WInput *in_with; /* Text */
135 static WInput *in_ignore;
136 static WLabel *content_label; /* 'Content:' label */
137 static WCheck *file_case_sens_cbox; /* "case sensitive" checkbox */
138 static WCheck *file_pattern_cbox; /* File name is glob or regexp */
139 static WCheck *recursively_cbox;
140 static WCheck *skip_hidden_cbox;
141 static WCheck *content_use_cbox; /* Take into account the Content field */
142 static WCheck *content_case_sens_cbox; /* "case sensitive" checkbox */
143 static WCheck *content_regexp_cbox; /* "find regular expression" checkbox */
144 static WCheck *content_first_hit_cbox; /* "First hit" checkbox" */
145 static WCheck *content_whole_words_cbox; /* "whole words" checkbox */
146 #ifdef HAVE_CHARSET
147 static WCheck *file_all_charsets_cbox;
148 static WCheck *content_all_charsets_cbox;
149 #endif
150 static WCheck *ignore_dirs_cbox;
152 static gboolean running = FALSE; /* nice flag */
153 static char *find_pattern = NULL; /* Pattern to search */
154 static char *content_pattern = NULL; /* pattern to search inside files; if
155 content_regexp_flag is true, it contains the
156 regex pattern, else the search string. */
157 static unsigned long matches; /* Number of matches */
158 static gboolean is_start = FALSE; /* Status of the start/stop toggle button */
159 static char *old_dir = NULL;
161 /* Where did we stop */
162 static int resuming;
163 static int last_line;
164 static int last_pos;
166 static size_t ignore_count = 0;
168 static Dlg_head *find_dlg; /* The dialog */
169 static WButton *stop_button; /* pointer to the stop button */
170 static WLabel *status_label; /* Finished, Searching etc. */
171 static WLabel *found_num_label; /* Number of found items */
172 static WListbox *find_list; /* Listbox with the file list */
174 /* This keeps track of the directory stack */
175 #if GLIB_CHECK_VERSION (2, 14, 0)
176 static GQueue dir_queue = G_QUEUE_INIT;
177 #else
178 typedef struct dir_stack
180 vfs_path_t *name;
181 struct dir_stack *prev;
182 } dir_stack;
184 static dir_stack *dir_stack_base = 0;
185 #endif /* GLIB_CHECK_VERSION */
187 /* *INDENT-OFF* */
188 static struct
190 const char *text;
191 int len; /* length including space and brackets */
192 int x;
193 } fbuts[] =
195 {N_("&Suspend"), 11, 29},
196 {N_("Con&tinue"), 12, 29},
197 {N_("&Chdir"), 11, 3},
198 {N_("&Again"), 9, 17},
199 {N_("&Quit"), 8, 43},
200 {N_("Pane&lize"), 12, 3},
201 {N_("&View - F3"), 13, 20},
202 {N_("&Edit - F4"), 13, 38}
204 /* *INDENT-ON* */
206 static find_file_options_t options = {
207 TRUE, TRUE, TRUE, FALSE, FALSE,
208 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE
211 static char *in_start_dir = INPUT_LAST_TEXT;
213 static mc_search_t *search_file_handle = NULL;
214 static mc_search_t *search_content_handle = NULL;
216 /*** file scope functions ************************************************************************/
218 static void
219 parse_ignore_dirs (const char *ignore_dirs)
221 size_t r = 0, w = 0; /* read and write iterators */
223 if (!options.ignore_dirs_enable || ignore_dirs == NULL || ignore_dirs[0] == '\0')
224 return;
226 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
228 /* Values like '/foo::/bar: produce holes in list.
229 * Find and remove them */
230 for (; find_ignore_dirs[r] != NULL; r++)
232 if (find_ignore_dirs[r][0] == '\0')
234 /* empty entry -- skip it */
235 g_free (find_ignore_dirs[r]);
236 find_ignore_dirs[r] = NULL;
237 continue;
240 if (r != w)
242 /* copy entry to the previous free array cell */
243 find_ignore_dirs[w] = find_ignore_dirs[r];
244 find_ignore_dirs[r] = NULL;
247 canonicalize_pathname (find_ignore_dirs[w]);
248 if (find_ignore_dirs[w][0] != '\0')
249 w++;
250 else
252 g_free (find_ignore_dirs[w]);
253 find_ignore_dirs[w] = NULL;
257 if (find_ignore_dirs[0] == NULL)
259 g_strfreev (find_ignore_dirs);
260 find_ignore_dirs = NULL;
264 /* --------------------------------------------------------------------------------------------- */
266 static void
267 find_load_options (void)
269 static gboolean loaded = FALSE;
271 if (loaded)
272 return;
274 loaded = TRUE;
276 options.file_case_sens =
277 mc_config_get_bool (mc_main_config, "FindFile", "file_case_sens", TRUE);
278 options.file_pattern =
279 mc_config_get_bool (mc_main_config, "FindFile", "file_shell_pattern", TRUE);
280 options.find_recurs = mc_config_get_bool (mc_main_config, "FindFile", "file_find_recurs", TRUE);
281 options.skip_hidden =
282 mc_config_get_bool (mc_main_config, "FindFile", "file_skip_hidden", FALSE);
283 options.file_all_charsets =
284 mc_config_get_bool (mc_main_config, "FindFile", "file_all_charsets", FALSE);
285 options.content_use = mc_config_get_bool (mc_main_config, "FindFile", "content_use", TRUE);
286 options.content_case_sens =
287 mc_config_get_bool (mc_main_config, "FindFile", "content_case_sens", TRUE);
288 options.content_regexp =
289 mc_config_get_bool (mc_main_config, "FindFile", "content_regexp", FALSE);
290 options.content_first_hit =
291 mc_config_get_bool (mc_main_config, "FindFile", "content_first_hit", FALSE);
292 options.content_whole_words =
293 mc_config_get_bool (mc_main_config, "FindFile", "content_whole_words", FALSE);
294 options.content_all_charsets =
295 mc_config_get_bool (mc_main_config, "FindFile", "content_all_charsets", FALSE);
296 options.ignore_dirs_enable =
297 mc_config_get_bool (mc_main_config, "FindFile", "ignore_dirs_enable", TRUE);
298 options.ignore_dirs = mc_config_get_string (mc_main_config, "FindFile", "ignore_dirs", "");
300 if (options.ignore_dirs[0] == '\0')
302 g_free (options.ignore_dirs);
303 options.ignore_dirs = NULL;
307 /* --------------------------------------------------------------------------------------------- */
309 static void
310 find_save_options (void)
312 mc_config_set_bool (mc_main_config, "FindFile", "file_case_sens", options.file_case_sens);
313 mc_config_set_bool (mc_main_config, "FindFile", "file_shell_pattern", options.file_pattern);
314 mc_config_set_bool (mc_main_config, "FindFile", "file_find_recurs", options.find_recurs);
315 mc_config_set_bool (mc_main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
316 mc_config_set_bool (mc_main_config, "FindFile", "file_all_charsets", options.file_all_charsets);
317 mc_config_set_bool (mc_main_config, "FindFile", "content_use", options.content_use);
318 mc_config_set_bool (mc_main_config, "FindFile", "content_case_sens", options.content_case_sens);
319 mc_config_set_bool (mc_main_config, "FindFile", "content_regexp", options.content_regexp);
320 mc_config_set_bool (mc_main_config, "FindFile", "content_first_hit", options.content_first_hit);
321 mc_config_set_bool (mc_main_config, "FindFile", "content_whole_words",
322 options.content_whole_words);
323 mc_config_set_bool (mc_main_config, "FindFile", "content_all_charsets",
324 options.content_all_charsets);
325 mc_config_set_bool (mc_main_config, "FindFile", "ignore_dirs_enable",
326 options.ignore_dirs_enable);
327 mc_config_set_string (mc_main_config, "FindFile", "ignore_dirs", options.ignore_dirs);
330 /* --------------------------------------------------------------------------------------------- */
332 static inline char *
333 add_to_list (const char *text, void *data)
335 return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data);
338 /* --------------------------------------------------------------------------------------------- */
340 static inline void
341 stop_idle (void *data)
343 set_idle_proc (data, 0);
346 /* --------------------------------------------------------------------------------------------- */
348 static inline void
349 status_update (const char *text)
351 label_set_text (status_label, text);
354 /* --------------------------------------------------------------------------------------------- */
356 static void
357 found_num_update (void)
359 char buffer[BUF_TINY];
360 g_snprintf (buffer, sizeof (buffer), _("Found: %ld"), matches);
361 label_set_text (found_num_label, buffer);
364 /* --------------------------------------------------------------------------------------------- */
366 static void
367 get_list_info (char **file, char **dir)
369 listbox_get_current (find_list, file, (void **) dir);
372 /* --------------------------------------------------------------------------------------------- */
373 /** check regular expression */
375 static gboolean
376 find_check_regexp (const char *r)
378 mc_search_t *search;
379 gboolean regexp_ok = FALSE;
381 search = mc_search_new (r, -1);
383 if (search != NULL)
385 search->search_type = MC_SEARCH_T_REGEX;
386 regexp_ok = mc_search_prepare (search);
387 mc_search_free (search);
390 return regexp_ok;
393 /* --------------------------------------------------------------------------------------------- */
395 * Callback for the parameter dialog.
396 * Validate regex, prevent closing the dialog if it's invalid.
399 static cb_ret_t
400 find_parm_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
402 switch (msg)
404 case DLG_ACTION:
405 if (sender == (Widget *) content_use_cbox)
407 gboolean disable = !(content_use_cbox->state & C_BOOL);
409 widget_disable (content_label->widget, disable);
410 send_message ((Widget *) content_label, WIDGET_DRAW, 0);
411 widget_disable (in_with->widget, disable);
412 send_message ((Widget *) in_with, WIDGET_DRAW, 0);
413 widget_disable (content_first_hit_cbox->widget, disable);
414 send_message ((Widget *) content_first_hit_cbox, WIDGET_DRAW, 0);
415 widget_disable (content_regexp_cbox->widget, disable);
416 send_message ((Widget *) content_regexp_cbox, WIDGET_DRAW, 0);
417 widget_disable (content_case_sens_cbox->widget, disable);
418 send_message ((Widget *) content_case_sens_cbox, WIDGET_DRAW, 0);
419 #ifdef HAVE_CHARSET
420 widget_disable (content_all_charsets_cbox->widget, disable);
421 send_message ((Widget *) content_all_charsets_cbox, WIDGET_DRAW, 0);
422 #endif
423 widget_disable (content_whole_words_cbox->widget, disable);
424 send_message ((Widget *) content_whole_words_cbox, WIDGET_DRAW, 0);
426 return MSG_HANDLED;
429 if (sender == (Widget *) ignore_dirs_cbox)
431 gboolean disable = !(ignore_dirs_cbox->state & C_BOOL);
433 widget_disable (in_ignore->widget, disable);
434 send_message ((Widget *) in_ignore, WIDGET_DRAW, 0);
436 return MSG_HANDLED;
439 return MSG_NOT_HANDLED;
442 case DLG_VALIDATE:
443 if (h->ret_value != B_ENTER)
444 return MSG_HANDLED;
446 /* check filename regexp */
447 if (!(file_pattern_cbox->state & C_BOOL)
448 && (in_name->buffer[0] != '\0') && !find_check_regexp (in_name->buffer))
450 h->state = DLG_ACTIVE; /* Don't stop the dialog */
451 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
452 dlg_select_widget (in_name);
453 return MSG_HANDLED;
456 /* check content regexp */
457 if ((content_use_cbox->state & C_BOOL) && (content_regexp_cbox->state & C_BOOL)
458 && (in_with->buffer[0] != '\0') && !find_check_regexp (in_with->buffer))
460 h->state = DLG_ACTIVE; /* Don't stop the dialog */
461 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
462 dlg_select_widget (in_with);
463 return MSG_HANDLED;
466 return MSG_HANDLED;
468 default:
469 return default_dlg_callback (h, sender, msg, parm, data);
473 /* --------------------------------------------------------------------------------------------- */
475 * find_parameters: gets information from the user
477 * If the return value is TRUE, then the following holds:
479 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
480 * They are newly allocated strings and must be freed when uneeded.
482 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
483 * of start_dir (which is absolute). It is used to get a relative pats of find results.
486 static gboolean
487 find_parameters (char **start_dir, ssize_t * start_dir_len,
488 char **ignore_dirs, char **pattern, char **content)
490 gboolean return_value;
492 /* file name */
493 const char *file_case_label = N_("Cas&e sensitive");
494 const char *file_pattern_label = N_("&Using shell patterns");
495 const char *file_recurs_label = N_("&Find recursively");
496 const char *file_skip_hidden_label = N_("S&kip hidden");
497 #ifdef HAVE_CHARSET
498 const char *file_all_charsets_label = N_("&All charsets");
499 #endif
501 /* file content */
502 const char *content_use_label = N_("Sea&rch for content");
503 const char *content_case_label = N_("Case sens&itive");
504 const char *content_regexp_label = N_("Re&gular expression");
505 const char *content_first_hit_label = N_("Fir&st hit");
506 const char *content_whole_words_label = N_("&Whole words");
507 #ifdef HAVE_CHARSET
508 const char *content_all_charsets_label = N_("A&ll charsets");
509 #endif
511 const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
513 int b0, b1, b2;
515 int cbox_position;
516 gboolean disable;
518 #ifdef ENABLE_NLS
520 int i = sizeof (buts) / sizeof (buts[0]);
521 while (i-- != 0)
522 buts[i] = _(buts[i]);
524 file_case_label = _(file_case_label);
525 file_pattern_label = _(file_pattern_label);
526 file_recurs_label = _(file_recurs_label);
527 file_skip_hidden_label = _(file_skip_hidden_label);
528 #ifdef HAVE_CHARSET
529 file_all_charsets_label = _(file_all_charsets_label);
530 content_all_charsets_label = _(content_all_charsets_label);
531 #endif
532 content_use_label = _(content_use_label);
533 content_case_label = _(content_case_label);
534 content_regexp_label = _(content_regexp_label);
535 content_first_hit_label = _(content_first_hit_label);
536 content_whole_words_label = _(content_whole_words_label);
538 #endif /* ENABLE_NLS */
540 b0 = str_term_width1 (buts[0]) + 6; /* default button */
541 b1 = str_term_width1 (buts[1]) + 4;
542 b2 = str_term_width1 (buts[2]) + 4;
544 find_load_options ();
546 if (in_start_dir == NULL)
547 in_start_dir = g_strdup (".");
549 disable = !options.content_use;
551 find_dlg =
552 create_dlg (TRUE, 0, 0, FIND_Y, FIND_X, dialog_colors,
553 find_parm_callback, "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
555 add_widget (find_dlg,
556 button_new (FIND_Y - 3, FIND_X * 3 / 4 - b1 / 2, B_CANCEL, NORMAL_BUTTON, buts[1],
557 0));
558 add_widget (find_dlg,
559 button_new (FIND_Y - 3, FIND_X / 4 - b0 / 2, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
561 cbox_position = FIND_Y - 5;
563 content_first_hit_cbox =
564 check_new (cbox_position--, FIND_X / 2 + 1, options.content_first_hit,
565 content_first_hit_label);
566 widget_disable (content_first_hit_cbox->widget, disable);
567 add_widget (find_dlg, content_first_hit_cbox);
569 content_whole_words_cbox =
570 check_new (cbox_position--, FIND_X / 2 + 1, options.content_whole_words,
571 content_whole_words_label);
572 widget_disable (content_whole_words_cbox->widget, disable);
573 add_widget (find_dlg, content_whole_words_cbox);
575 #ifdef HAVE_CHARSET
576 content_all_charsets_cbox = check_new (cbox_position--, FIND_X / 2 + 1,
577 options.content_all_charsets,
578 content_all_charsets_label);
579 widget_disable (content_all_charsets_cbox->widget, disable);
580 add_widget (find_dlg, content_all_charsets_cbox);
581 #endif
583 content_case_sens_cbox =
584 check_new (cbox_position--, FIND_X / 2 + 1, options.content_case_sens, content_case_label);
585 widget_disable (content_case_sens_cbox->widget, disable);
586 add_widget (find_dlg, content_case_sens_cbox);
588 content_regexp_cbox =
589 check_new (cbox_position--, FIND_X / 2 + 1, options.content_regexp, content_regexp_label);
590 widget_disable (content_regexp_cbox->widget, disable);
591 add_widget (find_dlg, content_regexp_cbox);
593 cbox_position = FIND_Y - 6;
595 skip_hidden_cbox = check_new (cbox_position--, 3, options.skip_hidden, file_skip_hidden_label);
596 add_widget (find_dlg, skip_hidden_cbox);
598 #ifdef HAVE_CHARSET
599 file_all_charsets_cbox =
600 check_new (cbox_position--, 3, options.file_all_charsets, file_all_charsets_label);
601 add_widget (find_dlg, file_all_charsets_cbox);
602 #endif
604 file_case_sens_cbox = check_new (cbox_position--, 3, options.file_case_sens, file_case_label);
605 add_widget (find_dlg, file_case_sens_cbox);
607 file_pattern_cbox = check_new (cbox_position--, 3, options.file_pattern, file_pattern_label);
608 add_widget (find_dlg, file_pattern_cbox);
610 recursively_cbox = check_new (cbox_position, 3, options.find_recurs, file_recurs_label);
611 add_widget (find_dlg, recursively_cbox);
613 /* This checkbox is located in the second column */
614 content_use_cbox =
615 check_new (cbox_position, FIND_X / 2 + 1, options.content_use, content_use_label);
616 add_widget (find_dlg, content_use_cbox);
618 in_with =
619 input_new (8, FIND_X / 2 + 1, input_get_default_colors (), FIND_X / 2 - 4, INPUT_LAST_TEXT,
620 MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_DEFAULT);
621 widget_disable (in_with->widget, disable);
622 add_widget (find_dlg, in_with);
624 content_label = label_new (7, FIND_X / 2 + 1, _("Content:"));
625 widget_disable (content_label->widget, disable);
626 add_widget (find_dlg, content_label);
628 in_name = input_new (8, 3, input_get_default_colors (),
629 FIND_X / 2 - 4, INPUT_LAST_TEXT, "name", INPUT_COMPLETE_DEFAULT);
630 add_widget (find_dlg, in_name);
631 add_widget (find_dlg, label_new (7, 3, _("File name:")));
633 in_ignore = input_new (5, 3, input_get_default_colors (), FIND_X - 6,
634 options.ignore_dirs != NULL ? options.ignore_dirs : "",
635 "ignoredirs", INPUT_COMPLETE_DEFAULT);
636 widget_disable (in_ignore->widget, !options.ignore_dirs_enable);
637 add_widget (find_dlg, in_ignore);
639 ignore_dirs_cbox =
640 check_new (4, 3, options.ignore_dirs_enable, _("Ena&ble ignore directories:"));
641 add_widget (find_dlg, ignore_dirs_cbox);
643 add_widget (find_dlg, button_new (3, FIND_X - b2 - 2, B_TREE, NORMAL_BUTTON, buts[2], 0));
645 in_start = input_new (3, 3, input_get_default_colors (),
646 FIND_X - b2 - 6, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
647 add_widget (find_dlg, in_start);
648 add_widget (find_dlg, label_new (2, 3, _("Start at:")));
650 find_par_start:
651 dlg_select_widget (in_name);
653 switch (run_dlg (find_dlg))
655 case B_CANCEL:
656 return_value = FALSE;
657 break;
659 case B_TREE:
661 char *temp_dir;
663 temp_dir = in_start->buffer;
664 if ((temp_dir[0] == '\0') || ((temp_dir[0] == '.') && (temp_dir[1] == '\0')))
665 temp_dir = vfs_path_to_str (current_panel->cwd_vpath);
666 else
667 temp_dir = g_strdup (temp_dir);
669 if (in_start_dir != INPUT_LAST_TEXT)
670 g_free (in_start_dir);
671 in_start_dir = tree_box (temp_dir);
672 if (in_start_dir == NULL)
673 in_start_dir = temp_dir;
674 else
675 g_free (temp_dir);
677 input_assign_text (in_start, in_start_dir);
679 /* Warning: Dreadful goto */
680 goto find_par_start;
683 default:
685 char *s;
687 #ifdef HAVE_CHARSET
688 options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
689 options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
690 #endif
691 options.content_use = content_use_cbox->state & C_BOOL;
692 options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
693 options.content_regexp = content_regexp_cbox->state & C_BOOL;
694 options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
695 options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
696 options.find_recurs = recursively_cbox->state & C_BOOL;
697 options.file_pattern = file_pattern_cbox->state & C_BOOL;
698 options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
699 options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
700 options.ignore_dirs_enable = ignore_dirs_cbox->state & C_BOOL;
701 g_free (options.ignore_dirs);
702 options.ignore_dirs = g_strdup (in_ignore->buffer);
704 *content = (options.content_use && in_with->buffer[0] != '\0')
705 ? g_strdup (in_with->buffer) : NULL;
706 *start_dir = in_start->buffer[0] != '\0' ? in_start->buffer : (char *) ".";
707 *pattern = g_strdup (in_name->buffer);
708 if (in_start_dir != INPUT_LAST_TEXT)
709 g_free (in_start_dir);
710 in_start_dir = g_strdup (*start_dir);
712 s = tilde_expand (*start_dir);
713 canonicalize_pathname (s);
715 if (s[0] == '.' && s[1] == '\0')
717 *start_dir = vfs_path_to_str (current_panel->cwd_vpath);
718 /* FIXME: is current_panel->cwd_vpath canonicalized? */
719 /* relative paths will be used in panelization */
720 *start_dir_len = (ssize_t) strlen (*start_dir);
721 g_free (s);
723 else if (g_path_is_absolute (s))
725 *start_dir = s;
726 *start_dir_len = -1;
728 else
730 /* relative paths will be used in panelization */
731 char *cwd_str;
733 cwd_str = vfs_path_to_str (current_panel->cwd_vpath);
734 *start_dir = mc_build_filename (cwd_str, s, (char *) NULL);
735 *start_dir_len = (ssize_t) strlen (cwd_str);
736 g_free (cwd_str);
737 g_free (s);
740 if (!options.ignore_dirs_enable || in_ignore->buffer[0] == '\0'
741 || (in_ignore->buffer[0] == '.' && in_ignore->buffer[1] == '\0'))
742 *ignore_dirs = NULL;
743 else
744 *ignore_dirs = g_strdup (in_ignore->buffer);
746 find_save_options ();
748 return_value = TRUE;
752 destroy_dlg (find_dlg);
754 return return_value;
757 /* --------------------------------------------------------------------------------------------- */
759 #if GLIB_CHECK_VERSION (2, 14, 0)
760 static inline void
761 push_directory (const vfs_path_t * dir)
763 g_queue_push_head (&dir_queue, (void *) dir);
766 /* --------------------------------------------------------------------------------------------- */
768 static inline vfs_path_t *
769 pop_directory (void)
771 return (vfs_path_t *) g_queue_pop_tail (&dir_queue);
774 /* --------------------------------------------------------------------------------------------- */
775 /** Remove all the items from the stack */
777 static void
778 clear_stack (void)
780 g_queue_foreach (&dir_queue, (GFunc) vfs_path_free, NULL);
781 g_queue_clear (&dir_queue);
784 /* --------------------------------------------------------------------------------------------- */
786 #else /* GLIB_CHECK_VERSION */
787 static void
788 push_directory (const vfs_path_t * dir)
790 dir_stack *new;
792 new = g_new (dir_stack, 1);
793 new->name = (vfs_path_t *) dir;
794 new->prev = dir_stack_base;
795 dir_stack_base = new;
798 /* --------------------------------------------------------------------------------------------- */
800 static vfs_path_t *
801 pop_directory (void)
803 vfs_path_t *name = NULL;
805 if (dir_stack_base != NULL)
807 dir_stack *next;
808 name = dir_stack_base->name;
809 next = dir_stack_base->prev;
810 g_free (dir_stack_base);
811 dir_stack_base = next;
814 return name;
817 /* --------------------------------------------------------------------------------------------- */
818 /** Remove all the items from the stack */
820 static void
821 clear_stack (void)
823 vfs_path_t *dir = NULL;
825 while ((dir = pop_directory ()) != NULL)
826 vfs_path_free (dir);
828 #endif /* GLIB_CHECK_VERSION */
830 /* --------------------------------------------------------------------------------------------- */
832 static void
833 insert_file (const char *dir, const char *file)
835 char *tmp_name = NULL;
836 static char *dirname = NULL;
838 while (dir[0] == PATH_SEP && dir[1] == PATH_SEP)
839 dir++;
841 if (old_dir)
843 if (strcmp (old_dir, dir))
845 g_free (old_dir);
846 old_dir = g_strdup (dir);
847 dirname = add_to_list (dir, NULL);
850 else
852 old_dir = g_strdup (dir);
853 dirname = add_to_list (dir, NULL);
856 tmp_name = g_strdup_printf (" %s", file);
857 add_to_list (tmp_name, dirname);
858 g_free (tmp_name);
861 /* --------------------------------------------------------------------------------------------- */
863 static void
864 find_add_match (const char *dir, const char *file)
866 insert_file (dir, file);
868 /* Don't scroll */
869 if (matches == 0)
870 listbox_select_first (find_list);
871 send_message (&find_list->widget, WIDGET_DRAW, 0);
873 matches++;
874 found_num_update ();
877 /* --------------------------------------------------------------------------------------------- */
879 * get_line_at:
881 * Returns malloced null-terminated line from file file_fd.
882 * Input is buffered in buf_size long buffer.
883 * Current pos in buf is stored in pos.
884 * n_read - number of read chars.
885 * has_newline - is there newline ?
888 static char *
889 get_line_at (int file_fd, char *buf, int buf_size, int *pos, int *n_read, gboolean * has_newline)
891 char *buffer = NULL;
892 int buffer_size = 0;
893 char ch = 0;
894 int i = 0;
896 for (;;)
898 if (*pos >= *n_read)
900 *pos = 0;
901 *n_read = mc_read (file_fd, buf, buf_size);
902 if (*n_read <= 0)
903 break;
906 ch = buf[(*pos)++];
907 if (ch == '\0')
909 /* skip possible leading zero(s) */
910 if (i == 0)
911 continue;
912 break;
915 if (i >= buffer_size - 1)
916 buffer = g_realloc (buffer, buffer_size += 80);
918 /* Strip newline */
919 if (ch == '\n')
920 break;
922 buffer[i++] = ch;
925 *has_newline = (ch != '\0');
927 if (buffer != NULL)
928 buffer[i] = '\0';
930 return buffer;
933 /* --------------------------------------------------------------------------------------------- */
935 static FindProgressStatus
936 check_find_events (Dlg_head * h)
938 Gpm_Event event;
939 int c;
941 event.x = -1;
942 c = tty_get_event (&event, h->mouse_status == MOU_REPEAT, FALSE);
943 if (c != EV_NONE)
945 dlg_process_event (h, c, &event);
946 if (h->ret_value == B_ENTER
947 || h->ret_value == B_CANCEL || h->ret_value == B_AGAIN || h->ret_value == B_PANELIZE)
949 /* dialog terminated */
950 return FIND_ABORT;
952 if (!(h->flags & DLG_WANT_IDLE))
954 /* searching suspended */
955 return FIND_SUSPEND;
959 return FIND_CONT;
962 /* --------------------------------------------------------------------------------------------- */
964 * search_content:
966 * Search the content_pattern string in the DIRECTORY/FILE.
967 * It will add the found entries to the find listbox.
969 * returns FALSE if do_search should look for another file
970 * TRUE if do_search should exit and proceed to the event handler
973 static gboolean
974 search_content (Dlg_head * h, const char *directory, const char *filename)
976 struct stat s;
977 char buffer[BUF_4K];
978 int file_fd;
979 gboolean ret_val = FALSE;
980 vfs_path_t *vpath;
982 vpath = vfs_path_build_filename (directory, filename, (char *) NULL);
984 if (mc_stat (vpath, &s) != 0 || !S_ISREG (s.st_mode))
986 vfs_path_free (vpath);
987 return FALSE;
990 file_fd = mc_open (vpath, O_RDONLY);
991 vfs_path_free (vpath);
993 if (file_fd == -1)
994 return FALSE;
996 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), str_trunc (filename, FIND2_X_USE));
998 status_update (buffer);
999 mc_refresh ();
1001 tty_enable_interrupt_key ();
1002 tty_got_interrupt ();
1005 int line = 1;
1006 int pos = 0;
1007 int n_read = 0;
1008 gboolean has_newline;
1009 char *p = NULL;
1010 gboolean found = FALSE;
1011 gsize found_len;
1012 char result[BUF_MEDIUM];
1014 if (resuming)
1016 /* We've been previously suspended, start from the previous position */
1017 resuming = 0;
1018 line = last_line;
1019 pos = last_pos;
1021 while (!ret_val
1022 && (p = get_line_at (file_fd, buffer, sizeof (buffer),
1023 &pos, &n_read, &has_newline)) != NULL)
1025 if (!found /* Search in binary line once */
1026 && mc_search_run (search_content_handle,
1027 (const void *) p, 0, strlen (p), &found_len))
1029 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
1030 find_add_match (directory, result);
1031 found = TRUE;
1033 g_free (p);
1035 if (found && options.content_first_hit)
1036 break;
1038 if (has_newline)
1040 found = FALSE;
1041 line++;
1044 if ((line & 0xff) == 0)
1046 FindProgressStatus res;
1047 res = check_find_events (h);
1048 switch (res)
1050 case FIND_ABORT:
1051 stop_idle (h);
1052 ret_val = TRUE;
1053 break;
1054 case FIND_SUSPEND:
1055 resuming = 1;
1056 last_line = line;
1057 last_pos = pos;
1058 ret_val = TRUE;
1059 break;
1060 default:
1061 break;
1066 tty_disable_interrupt_key ();
1067 mc_close (file_fd);
1068 return ret_val;
1071 /* --------------------------------------------------------------------------------------------- */
1074 If dir is absolute, this means we're within dir and searching file here.
1075 If dir is relative, this means we're going to add dir to the directory stack.
1077 static gboolean
1078 find_ignore_dir_search (const char *dir)
1080 if (find_ignore_dirs != NULL)
1082 const size_t dlen = strlen (dir);
1083 const unsigned char dabs = g_path_is_absolute (dir) ? 1 : 0;
1085 char **ignore_dir;
1087 for (ignore_dir = find_ignore_dirs; *ignore_dir != NULL; ignore_dir++)
1089 const size_t ilen = strlen (*ignore_dir);
1090 const unsigned char iabs = g_path_is_absolute (*ignore_dir) ? 2 : 0;
1092 /* ignore dir is too long -- skip it */
1093 if (dlen < ilen)
1094 continue;
1096 /* handle absolute and relative paths */
1097 switch (iabs | dabs)
1099 case 0: /* both paths are relative */
1100 case 3: /* both paths are abolute */
1101 /* if ignore dir is not a path of dir -- skip it */
1102 if (strncmp (dir, *ignore_dir, ilen) == 0)
1104 /* be sure that ignore dir is not a part of dir like:
1105 ignore dir is "h", dir is "home" */
1106 if (dir[ilen] == '\0' || dir[ilen] == PATH_SEP)
1107 return TRUE;
1109 break;
1110 case 1: /* dir is absolute, ignore_dir is relative */
1112 char *d;
1114 d = strstr (dir, *ignore_dir);
1115 if (d != NULL && d[-1] == PATH_SEP && (d[ilen] == '\0' || d[ilen] == PATH_SEP))
1116 return TRUE;
1118 break;
1119 case 2: /* dir is relative, ignore_dir is absolute */
1120 /* FIXME: skip this case */
1121 break;
1122 default: /* this cannot occurs */
1123 return FALSE;
1128 return FALSE;
1131 /* --------------------------------------------------------------------------------------------- */
1133 static void
1134 find_rotate_dash (const Dlg_head * h, gboolean finish)
1136 static const char rotating_dash[] = "|/-\\";
1137 static unsigned int pos = 0;
1139 if (verbose)
1141 pos = (pos + 1) % 4;
1142 tty_setcolor (h->color[DLG_COLOR_NORMAL]);
1143 dlg_move (h, FIND2_Y - 7, FIND2_X - 4);
1144 tty_print_char (finish ? ' ' : rotating_dash[pos]);
1145 mc_refresh ();
1149 /* --------------------------------------------------------------------------------------------- */
1151 static int
1152 do_search (Dlg_head * h)
1154 static struct dirent *dp = NULL;
1155 static DIR *dirp = NULL;
1156 static char *directory = NULL;
1157 struct stat tmp_stat;
1158 static int subdirs_left = 0;
1159 gsize bytes_found;
1160 unsigned short count;
1162 if (h == NULL)
1163 { /* someone forces me to close dirp */
1164 if (dirp != NULL)
1166 mc_closedir (dirp);
1167 dirp = NULL;
1169 g_free (directory);
1170 directory = NULL;
1171 dp = NULL;
1172 return 1;
1175 for (count = 0; count < 32; count++)
1177 while (dp == NULL)
1179 if (dirp != NULL)
1181 mc_closedir (dirp);
1182 dirp = NULL;
1185 while (dirp == NULL)
1187 vfs_path_t *tmp_vpath = NULL;
1189 tty_setcolor (REVERSE_COLOR);
1191 while (TRUE)
1193 tmp_vpath = pop_directory ();
1194 if (tmp_vpath == NULL)
1196 running = FALSE;
1197 if (ignore_count == 0)
1198 status_update (_("Finished"));
1199 else
1201 char msg[BUF_SMALL];
1202 g_snprintf (msg, sizeof (msg),
1203 ngettext ("Finished (ignored %zd directory)",
1204 "Finished (ignored %zd directories)",
1205 ignore_count), ignore_count);
1206 status_update (msg);
1208 find_rotate_dash (h, TRUE);
1209 stop_idle (h);
1210 return 0;
1213 /* handle absolute ignore dirs here */
1215 char *tmp;
1216 gboolean ok;
1218 tmp = vfs_path_to_str (tmp_vpath);
1219 ok = find_ignore_dir_search (tmp);
1220 g_free (tmp);
1221 if (!ok)
1222 break;
1225 vfs_path_free (tmp_vpath);
1226 ignore_count++;
1229 g_free (directory);
1230 directory = vfs_path_to_str (tmp_vpath);
1232 if (verbose)
1234 char buffer[BUF_SMALL];
1236 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
1237 str_trunc (directory, FIND2_X_USE));
1238 status_update (buffer);
1240 /* mc_stat should not be called after mc_opendir
1241 because vfs_s_opendir modifies the st_nlink
1243 if (mc_stat (tmp_vpath, &tmp_stat) == 0)
1244 subdirs_left = tmp_stat.st_nlink - 2;
1245 else
1246 subdirs_left = 0;
1248 dirp = mc_opendir (tmp_vpath);
1249 vfs_path_free (tmp_vpath);
1250 } /* while (!dirp) */
1252 /* skip invalid filenames */
1253 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1255 } /* while (!dp) */
1257 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
1259 /* skip invalid filenames */
1260 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1263 return 1;
1266 if (!(options.skip_hidden && (dp->d_name[0] == '.')))
1268 gboolean search_ok;
1270 if ((subdirs_left != 0) && options.find_recurs && (directory != NULL))
1271 { /* Can directory be NULL ? */
1272 /* handle relative ignore dirs here */
1273 if (options.ignore_dirs_enable && find_ignore_dir_search (dp->d_name))
1274 ignore_count++;
1275 else
1277 vfs_path_t *tmp_vpath;
1279 tmp_vpath = vfs_path_build_filename (directory, dp->d_name, (char *) NULL);
1281 if (mc_lstat (tmp_vpath, &tmp_stat) == 0 && S_ISDIR (tmp_stat.st_mode))
1283 push_directory (tmp_vpath);
1284 subdirs_left--;
1286 else
1287 vfs_path_free (tmp_vpath);
1291 search_ok = mc_search_run (search_file_handle, dp->d_name,
1292 0, strlen (dp->d_name), &bytes_found);
1294 if (search_ok)
1296 if (content_pattern == NULL)
1297 find_add_match (directory, dp->d_name);
1298 else if (search_content (h, directory, dp->d_name))
1299 return 1;
1303 /* skip invalid filenames */
1304 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1306 } /* for */
1308 find_rotate_dash (h, FALSE);
1310 return 1;
1313 /* --------------------------------------------------------------------------------------------- */
1315 static void
1316 init_find_vars (void)
1318 g_free (old_dir);
1319 old_dir = NULL;
1320 matches = 0;
1321 ignore_count = 0;
1323 /* Remove all the items from the stack */
1324 clear_stack ();
1326 g_strfreev (find_ignore_dirs);
1327 find_ignore_dirs = NULL;
1330 /* --------------------------------------------------------------------------------------------- */
1332 static void
1333 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
1335 char *fullname = NULL;
1336 const char *filename = NULL;
1337 int line;
1338 vfs_path_t *fullname_vpath;
1340 if (content_pattern != NULL)
1342 filename = strchr (file + 4, ':') + 1;
1343 line = atoi (file + 4);
1345 else
1347 filename = file + 4;
1348 line = 0;
1351 fullname_vpath = vfs_path_build_filename (dir, filename, (char *) NULL);
1352 if (edit)
1353 do_edit_at_line (fullname_vpath, use_internal_edit, line);
1354 else
1355 view_file_at_line (fullname_vpath, unparsed_view, use_internal_view, line);
1356 vfs_path_free (fullname_vpath);
1357 g_free (fullname);
1360 /* --------------------------------------------------------------------------------------------- */
1362 static cb_ret_t
1363 view_edit_currently_selected_file (int unparsed_view, int edit)
1365 char *dir = NULL;
1366 char *text = NULL;
1368 listbox_get_current (find_list, &text, (void **) &dir);
1370 if ((text == NULL) || (dir == NULL))
1371 return MSG_NOT_HANDLED;
1373 find_do_view_edit (unparsed_view, edit, dir, text);
1374 return MSG_HANDLED;
1377 /* --------------------------------------------------------------------------------------------- */
1379 static cb_ret_t
1380 find_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
1382 switch (msg)
1384 case DLG_KEY:
1385 if (parm == KEY_F (3) || parm == KEY_F (13))
1387 int unparsed_view = (parm == KEY_F (13));
1388 return view_edit_currently_selected_file (unparsed_view, 0);
1390 if (parm == KEY_F (4))
1392 return view_edit_currently_selected_file (0, 1);
1394 return MSG_NOT_HANDLED;
1396 case DLG_IDLE:
1397 do_search (h);
1398 return MSG_HANDLED;
1400 default:
1401 return default_dlg_callback (h, sender, msg, parm, data);
1405 /* --------------------------------------------------------------------------------------------- */
1406 /** Handles the Stop/Start button in the find window */
1408 static int
1409 start_stop (WButton * button, int action)
1411 (void) button;
1412 (void) action;
1414 running = is_start;
1415 set_idle_proc (find_dlg, running);
1416 is_start = !is_start;
1418 status_update (is_start ? _("Stopped") : _("Searching"));
1419 button_set_text (stop_button, fbuts[is_start ? 1 : 0].text);
1421 return 0;
1424 /* --------------------------------------------------------------------------------------------- */
1425 /** Handle view command, when invoked as a button */
1427 static int
1428 find_do_view_file (WButton * button, int action)
1430 (void) button;
1431 (void) action;
1433 view_edit_currently_selected_file (0, 0);
1434 return 0;
1437 /* --------------------------------------------------------------------------------------------- */
1438 /** Handle edit command, when invoked as a button */
1440 static int
1441 find_do_edit_file (WButton * button, int action)
1443 (void) button;
1444 (void) action;
1446 view_edit_currently_selected_file (0, 1);
1447 return 0;
1450 /* --------------------------------------------------------------------------------------------- */
1452 static void
1453 setup_gui (void)
1455 #ifdef ENABLE_NLS
1456 static gboolean i18n_flag = FALSE;
1458 if (!i18n_flag)
1460 int i = sizeof (fbuts) / sizeof (fbuts[0]);
1461 while (i-- != 0)
1463 fbuts[i].text = _(fbuts[i].text);
1464 fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1467 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
1468 i18n_flag = TRUE;
1470 #endif /* ENABLE_NLS */
1473 * Dynamically place buttons centered within current window size
1476 int l0 = max (fbuts[0].len, fbuts[1].len);
1477 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
1478 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
1479 int r1, r2;
1481 /* Check, if both button rows fit within FIND2_X */
1482 FIND2_X = max (l1 + 9, COLS - 16);
1483 FIND2_X = max (l2 + 8, FIND2_X);
1485 /* compute amount of space between buttons for each row */
1486 r1 = (FIND2_X - 4 - l1) % 5;
1487 l1 = (FIND2_X - 4 - l1) / 5;
1488 r2 = (FIND2_X - 4 - l2) % 4;
1489 l2 = (FIND2_X - 4 - l2) / 4;
1491 /* ...and finally, place buttons */
1492 fbuts[2].x = 2 + r1 / 2 + l1;
1493 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
1494 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
1495 fbuts[4].x = fbuts[0].x + l0 + l1;
1496 fbuts[5].x = 2 + r2 / 2 + l2;
1497 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
1498 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
1501 find_dlg =
1502 create_dlg (TRUE, 0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
1503 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
1505 add_widget (find_dlg,
1506 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
1507 fbuts[7].text, find_do_edit_file));
1508 add_widget (find_dlg,
1509 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
1510 fbuts[6].text, find_do_view_file));
1511 add_widget (find_dlg,
1512 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON, fbuts[5].text,
1513 NULL));
1515 add_widget (find_dlg,
1516 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON, fbuts[4].text, NULL));
1517 stop_button =
1518 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON, fbuts[0].text, start_stop);
1519 add_widget (find_dlg, stop_button);
1520 add_widget (find_dlg,
1521 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON, fbuts[3].text, NULL));
1522 add_widget (find_dlg,
1523 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON, fbuts[2].text, NULL));
1525 status_label = label_new (FIND2_Y - 7, 4, _("Searching"));
1526 add_widget (find_dlg, status_label);
1528 found_num_label = label_new (FIND2_Y - 6, 4, "");
1529 add_widget (find_dlg, found_num_label);
1531 find_list = listbox_new (2, 2, FIND2_Y - 10, FIND2_X - 4, FALSE, NULL);
1532 add_widget (find_dlg, find_list);
1535 /* --------------------------------------------------------------------------------------------- */
1537 static int
1538 run_process (void)
1540 int ret;
1542 search_content_handle = mc_search_new (content_pattern, -1);
1543 if (search_content_handle)
1545 search_content_handle->search_type =
1546 options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
1547 search_content_handle->is_case_sensitive = options.content_case_sens;
1548 search_content_handle->whole_words = options.content_whole_words;
1549 search_content_handle->is_all_charsets = options.content_all_charsets;
1551 search_file_handle = mc_search_new (find_pattern, -1);
1552 search_file_handle->search_type = options.file_pattern ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
1553 search_file_handle->is_case_sensitive = options.file_case_sens;
1554 search_file_handle->is_all_charsets = options.file_all_charsets;
1555 search_file_handle->is_entire_line = options.file_pattern;
1557 resuming = 0;
1559 set_idle_proc (find_dlg, 1);
1560 ret = run_dlg (find_dlg);
1562 mc_search_free (search_file_handle);
1563 search_file_handle = NULL;
1564 mc_search_free (search_content_handle);
1565 search_content_handle = NULL;
1567 return ret;
1570 /* --------------------------------------------------------------------------------------------- */
1572 static void
1573 kill_gui (void)
1575 set_idle_proc (find_dlg, 0);
1576 destroy_dlg (find_dlg);
1579 /* --------------------------------------------------------------------------------------------- */
1581 static int
1582 do_find (const char *start_dir, ssize_t start_dir_len, const char *ignore_dirs,
1583 const char *pattern, const char *content, char **dirname, char **filename)
1585 int return_value = 0;
1586 char *dir_tmp = NULL, *file_tmp = NULL;
1588 setup_gui ();
1590 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1591 find_pattern = (char *) pattern;
1593 content_pattern = NULL;
1594 if (options.content_use && content != NULL && str_is_valid_string (content))
1595 content_pattern = g_strdup (content);
1597 init_find_vars ();
1598 parse_ignore_dirs (ignore_dirs);
1599 push_directory (vfs_path_from_str (start_dir));
1601 return_value = run_process ();
1603 /* Clear variables */
1604 init_find_vars ();
1606 get_list_info (&file_tmp, &dir_tmp);
1608 if (dir_tmp)
1609 *dirname = g_strdup (dir_tmp);
1610 if (file_tmp)
1611 *filename = g_strdup (file_tmp);
1613 if (return_value == B_PANELIZE && *filename)
1615 int status, link_to_dir, stale_link;
1616 int next_free = 0;
1617 int i;
1618 struct stat st;
1619 GList *entry;
1620 dir_list *list = &current_panel->dir;
1621 char *name = NULL;
1623 if (set_zero_dir (list))
1624 next_free++;
1626 for (i = 0, entry = find_list->list; entry != NULL; i++, entry = g_list_next (entry))
1628 const char *lc_filename = NULL;
1629 WLEntry *le = (WLEntry *) entry->data;
1630 char *p;
1632 if ((le->text == NULL) || (le->data == NULL))
1633 continue;
1635 if (content_pattern != NULL)
1636 lc_filename = strchr (le->text + 4, ':') + 1;
1637 else
1638 lc_filename = le->text + 4;
1640 name = mc_build_filename (le->data, lc_filename, (char *) NULL);
1641 /* skip initial start dir */
1642 if (start_dir_len < 0)
1643 p = name;
1644 else
1646 p = name + (size_t) start_dir_len;
1647 if (*p == PATH_SEP)
1648 p++;
1651 status = handle_path (list, p, &st, next_free, &link_to_dir, &stale_link);
1652 if (status == 0)
1654 g_free (name);
1655 continue;
1657 if (status == -1)
1659 g_free (name);
1660 break;
1663 /* don't add files more than once to the panel */
1664 if (content_pattern != NULL && next_free > 0
1665 && strcmp (list->list[next_free - 1].fname, p) == 0)
1667 g_free (name);
1668 continue;
1671 if (next_free == 0) /* first turn i.e clean old list */
1672 panel_clean_dir (current_panel);
1673 list->list[next_free].fnamelen = strlen (p);
1674 list->list[next_free].fname = g_strndup (p, list->list[next_free].fnamelen);
1675 list->list[next_free].f.marked = 0;
1676 list->list[next_free].f.link_to_dir = link_to_dir;
1677 list->list[next_free].f.stale_link = stale_link;
1678 list->list[next_free].f.dir_size_computed = 0;
1679 list->list[next_free].st = st;
1680 list->list[next_free].sort_key = NULL;
1681 list->list[next_free].second_sort_key = NULL;
1682 next_free++;
1683 g_free (name);
1684 if (!(next_free & 15))
1685 rotate_dash ();
1688 if (next_free)
1690 current_panel->count = next_free;
1691 current_panel->is_panelized = TRUE;
1693 /* absolute path */
1694 if (start_dir_len < 0)
1696 int ret;
1697 vfs_path_free (current_panel->cwd_vpath);
1698 current_panel->cwd_vpath = vfs_path_from_str (PATH_SEP_STR);
1699 ret = chdir (PATH_SEP_STR);
1701 panelize_save_panel (current_panel);
1705 g_free (content_pattern);
1706 kill_gui ();
1707 do_search (NULL); /* force do_search to release resources */
1708 g_free (old_dir);
1709 old_dir = NULL;
1711 return return_value;
1714 /* --------------------------------------------------------------------------------------------- */
1715 /*** public functions ****************************************************************************/
1716 /* --------------------------------------------------------------------------------------------- */
1718 void
1719 find_file (void)
1721 char *start_dir = NULL, *pattern = NULL, *content = NULL, *ignore_dirs = NULL;
1722 ssize_t start_dir_len;
1723 char *filename = NULL, *dirname = NULL;
1724 int v;
1726 while (find_parameters (&start_dir, &start_dir_len, &ignore_dirs, &pattern, &content))
1728 if (pattern[0] == '\0')
1729 break; /* nothing search */
1731 dirname = filename = NULL;
1732 is_start = FALSE;
1733 v = do_find (start_dir, start_dir_len, ignore_dirs, pattern, content, &dirname, &filename);
1734 g_free (ignore_dirs);
1735 g_free (pattern);
1737 if (v == B_ENTER)
1739 if (dirname != NULL)
1741 vfs_path_t *dirname_vpath;
1743 dirname_vpath = vfs_path_from_str (dirname);
1744 do_cd (dirname_vpath, cd_exact);
1745 vfs_path_free (dirname_vpath);
1746 if (filename != NULL)
1747 try_to_select (current_panel,
1748 filename + (content != NULL
1749 ? strchr (filename + 4, ':') - filename + 1 : 4));
1751 else if (filename != NULL)
1753 vfs_path_t *filename_vpath;
1755 filename_vpath = vfs_path_from_str (filename);
1756 do_cd (filename_vpath, cd_exact);
1757 vfs_path_free (filename_vpath);
1760 g_free (dirname);
1761 g_free (filename);
1762 break;
1765 g_free (content);
1766 g_free (dirname);
1767 g_free (filename);
1769 if (v == B_CANCEL)
1770 break;
1772 if (v == B_PANELIZE)
1774 panel_re_sort (current_panel);
1775 try_to_select (current_panel, NULL);
1776 break;
1781 /* --------------------------------------------------------------------------------------------- */