Added macros for Layout and Misc sections of main config file.
[midnight-commander.git] / src / filemanager / find.c
blobb4208011cc914871149e0140fbefc3efd1a241bf
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 #if 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 char *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;
270 char *ignore_dirs;
272 if (loaded)
273 return;
275 loaded = TRUE;
277 options.file_case_sens =
278 mc_config_get_bool (mc_main_config, "FindFile", "file_case_sens", TRUE);
279 options.file_pattern =
280 mc_config_get_bool (mc_main_config, "FindFile", "file_shell_pattern", TRUE);
281 options.find_recurs = mc_config_get_bool (mc_main_config, "FindFile", "file_find_recurs", TRUE);
282 options.skip_hidden =
283 mc_config_get_bool (mc_main_config, "FindFile", "file_skip_hidden", FALSE);
284 options.file_all_charsets =
285 mc_config_get_bool (mc_main_config, "FindFile", "file_all_charsets", FALSE);
286 options.content_use = mc_config_get_bool (mc_main_config, "FindFile", "content_use", TRUE);
287 options.content_case_sens =
288 mc_config_get_bool (mc_main_config, "FindFile", "content_case_sens", TRUE);
289 options.content_regexp =
290 mc_config_get_bool (mc_main_config, "FindFile", "content_regexp", FALSE);
291 options.content_first_hit =
292 mc_config_get_bool (mc_main_config, "FindFile", "content_first_hit", FALSE);
293 options.content_whole_words =
294 mc_config_get_bool (mc_main_config, "FindFile", "content_whole_words", FALSE);
295 options.content_all_charsets =
296 mc_config_get_bool (mc_main_config, "FindFile", "content_all_charsets", FALSE);
297 options.ignore_dirs_enable =
298 mc_config_get_bool (mc_main_config, "FindFile", "ignore_dirs_enable", TRUE);
300 /* Back compatibility: try load old parameter at first */
301 ignore_dirs = mc_config_get_string (mc_main_config, CONFIG_MISC_SECTION, "find_ignore_dirs", "");
302 mc_config_del_key (mc_main_config, CONFIG_MISC_SECTION, "find_ignore_dirs");
304 /* Then load new parameters */
305 options.ignore_dirs = mc_config_get_string (mc_main_config, "FindFile", "ignore_dirs", "");
306 if (options.ignore_dirs[0] != '\0')
307 g_free (ignore_dirs);
308 else
310 g_free (options.ignore_dirs);
311 options.ignore_dirs = ignore_dirs;
314 if (options.ignore_dirs[0] == '\0')
316 g_free (options.ignore_dirs);
317 options.ignore_dirs = NULL;
321 /* --------------------------------------------------------------------------------------------- */
323 static void
324 find_save_options (void)
326 mc_config_set_bool (mc_main_config, "FindFile", "file_case_sens", options.file_case_sens);
327 mc_config_set_bool (mc_main_config, "FindFile", "file_shell_pattern", options.file_pattern);
328 mc_config_set_bool (mc_main_config, "FindFile", "file_find_recurs", options.find_recurs);
329 mc_config_set_bool (mc_main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
330 mc_config_set_bool (mc_main_config, "FindFile", "file_all_charsets", options.file_all_charsets);
331 mc_config_set_bool (mc_main_config, "FindFile", "content_use", options.content_use);
332 mc_config_set_bool (mc_main_config, "FindFile", "content_case_sens", options.content_case_sens);
333 mc_config_set_bool (mc_main_config, "FindFile", "content_regexp", options.content_regexp);
334 mc_config_set_bool (mc_main_config, "FindFile", "content_first_hit", options.content_first_hit);
335 mc_config_set_bool (mc_main_config, "FindFile", "content_whole_words",
336 options.content_whole_words);
337 mc_config_set_bool (mc_main_config, "FindFile", "content_all_charsets",
338 options.content_all_charsets);
339 mc_config_set_bool (mc_main_config, "FindFile", "ignore_dirs_enable",
340 options.ignore_dirs_enable);
341 mc_config_set_string (mc_main_config, "FindFile", "ignore_dirs", options.ignore_dirs);
344 /* --------------------------------------------------------------------------------------------- */
346 static inline char *
347 add_to_list (const char *text, void *data)
349 return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data);
352 /* --------------------------------------------------------------------------------------------- */
354 static inline void
355 stop_idle (void *data)
357 set_idle_proc (data, 0);
360 /* --------------------------------------------------------------------------------------------- */
362 static inline void
363 status_update (const char *text)
365 label_set_text (status_label, text);
368 /* --------------------------------------------------------------------------------------------- */
370 static void
371 found_num_update (void)
373 char buffer[BUF_TINY];
374 g_snprintf (buffer, sizeof (buffer), _("Found: %ld"), matches);
375 label_set_text (found_num_label, buffer);
378 /* --------------------------------------------------------------------------------------------- */
380 static void
381 get_list_info (char **file, char **dir)
383 listbox_get_current (find_list, file, (void **) dir);
386 /* --------------------------------------------------------------------------------------------- */
387 /** check regular expression */
389 static gboolean
390 find_check_regexp (const char *r)
392 mc_search_t *search;
393 gboolean regexp_ok = FALSE;
395 search = mc_search_new (r, -1);
397 if (search != NULL)
399 search->search_type = MC_SEARCH_T_REGEX;
400 regexp_ok = mc_search_prepare (search);
401 mc_search_free (search);
404 return regexp_ok;
407 /* --------------------------------------------------------------------------------------------- */
409 * Callback for the parameter dialog.
410 * Validate regex, prevent closing the dialog if it's invalid.
413 static cb_ret_t
414 find_parm_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
416 switch (msg)
418 case DLG_ACTION:
419 if (sender == (Widget *) content_use_cbox)
421 gboolean disable = !(content_use_cbox->state & C_BOOL);
423 widget_disable (content_label->widget, disable);
424 send_message ((Widget *) content_label, WIDGET_DRAW, 0);
425 widget_disable (in_with->widget, disable);
426 send_message ((Widget *) in_with, WIDGET_DRAW, 0);
427 widget_disable (content_first_hit_cbox->widget, disable);
428 send_message ((Widget *) content_first_hit_cbox, WIDGET_DRAW, 0);
429 widget_disable (content_regexp_cbox->widget, disable);
430 send_message ((Widget *) content_regexp_cbox, WIDGET_DRAW, 0);
431 widget_disable (content_case_sens_cbox->widget, disable);
432 send_message ((Widget *) content_case_sens_cbox, WIDGET_DRAW, 0);
433 #ifdef HAVE_CHARSET
434 widget_disable (content_all_charsets_cbox->widget, disable);
435 send_message ((Widget *) content_all_charsets_cbox, WIDGET_DRAW, 0);
436 #endif
437 widget_disable (content_whole_words_cbox->widget, disable);
438 send_message ((Widget *) content_whole_words_cbox, WIDGET_DRAW, 0);
440 return MSG_HANDLED;
443 if (sender == (Widget *) ignore_dirs_cbox)
445 gboolean disable = !(ignore_dirs_cbox->state & C_BOOL);
447 widget_disable (in_ignore->widget, disable);
448 send_message ((Widget *) in_ignore, WIDGET_DRAW, 0);
450 return MSG_HANDLED;
453 return MSG_NOT_HANDLED;
456 case DLG_VALIDATE:
457 if (h->ret_value != B_ENTER)
458 return MSG_HANDLED;
460 /* check filename regexp */
461 if (!(file_pattern_cbox->state & C_BOOL)
462 && (in_name->buffer[0] != '\0') && !find_check_regexp (in_name->buffer))
464 h->state = DLG_ACTIVE; /* Don't stop the dialog */
465 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
466 dlg_select_widget (in_name);
467 return MSG_HANDLED;
470 /* check content regexp */
471 if ((content_use_cbox->state & C_BOOL) && (content_regexp_cbox->state & C_BOOL)
472 && (in_with->buffer[0] != '\0') && !find_check_regexp (in_with->buffer))
474 h->state = DLG_ACTIVE; /* Don't stop the dialog */
475 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
476 dlg_select_widget (in_with);
477 return MSG_HANDLED;
480 return MSG_HANDLED;
482 default:
483 return default_dlg_callback (h, sender, msg, parm, data);
487 /* --------------------------------------------------------------------------------------------- */
489 * find_parameters: gets information from the user
491 * If the return value is TRUE, then the following holds:
493 * start_dir, ignore_dirs, pattern and content contain the information provided by the user.
494 * They are newly allocated strings and must be freed when uneeded.
496 * start_dir_len is -1 when user entered an absolute path, otherwise it is a length
497 * of start_dir (which is absolute). It is used to get a relative pats of find results.
500 static gboolean
501 find_parameters (char **start_dir, ssize_t * start_dir_len,
502 char **ignore_dirs, char **pattern, char **content)
504 gboolean return_value;
506 /* file name */
507 const char *file_case_label = N_("Cas&e sensitive");
508 const char *file_pattern_label = N_("&Using shell patterns");
509 const char *file_recurs_label = N_("&Find recursively");
510 const char *file_skip_hidden_label = N_("S&kip hidden");
511 #ifdef HAVE_CHARSET
512 const char *file_all_charsets_label = N_("&All charsets");
513 #endif
515 /* file content */
516 const char *content_use_label = N_("Sea&rch for content");
517 const char *content_case_label = N_("Case sens&itive");
518 const char *content_regexp_label = N_("Re&gular expression");
519 const char *content_first_hit_label = N_("Fir&st hit");
520 const char *content_whole_words_label = N_("&Whole words");
521 #ifdef HAVE_CHARSET
522 const char *content_all_charsets_label = N_("A&ll charsets");
523 #endif
525 const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
527 int b0, b1, b2;
529 int cbox_position;
530 gboolean disable;
532 #ifdef ENABLE_NLS
534 int i = sizeof (buts) / sizeof (buts[0]);
535 while (i-- != 0)
536 buts[i] = _(buts[i]);
538 file_case_label = _(file_case_label);
539 file_pattern_label = _(file_pattern_label);
540 file_recurs_label = _(file_recurs_label);
541 file_skip_hidden_label = _(file_skip_hidden_label);
542 #ifdef HAVE_CHARSET
543 file_all_charsets_label = _(file_all_charsets_label);
544 content_all_charsets_label = _(content_all_charsets_label);
545 #endif
546 content_use_label = _(content_use_label);
547 content_case_label = _(content_case_label);
548 content_regexp_label = _(content_regexp_label);
549 content_first_hit_label = _(content_first_hit_label);
550 content_whole_words_label = _(content_whole_words_label);
552 #endif /* ENABLE_NLS */
554 b0 = str_term_width1 (buts[0]) + 6; /* default button */
555 b1 = str_term_width1 (buts[1]) + 4;
556 b2 = str_term_width1 (buts[2]) + 4;
558 find_load_options ();
560 if (in_start_dir == NULL)
561 in_start_dir = g_strdup (".");
563 disable = !options.content_use;
565 find_dlg =
566 create_dlg (TRUE, 0, 0, FIND_Y, FIND_X, dialog_colors,
567 find_parm_callback, "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
569 add_widget (find_dlg,
570 button_new (FIND_Y - 3, FIND_X * 3 / 4 - b1 / 2, B_CANCEL, NORMAL_BUTTON, buts[1],
571 0));
572 add_widget (find_dlg,
573 button_new (FIND_Y - 3, FIND_X / 4 - b0 / 2, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
575 cbox_position = FIND_Y - 5;
577 content_first_hit_cbox =
578 check_new (cbox_position--, FIND_X / 2 + 1, options.content_first_hit,
579 content_first_hit_label);
580 widget_disable (content_first_hit_cbox->widget, disable);
581 add_widget (find_dlg, content_first_hit_cbox);
583 content_whole_words_cbox =
584 check_new (cbox_position--, FIND_X / 2 + 1, options.content_whole_words,
585 content_whole_words_label);
586 widget_disable (content_whole_words_cbox->widget, disable);
587 add_widget (find_dlg, content_whole_words_cbox);
589 #ifdef HAVE_CHARSET
590 content_all_charsets_cbox = check_new (cbox_position--, FIND_X / 2 + 1,
591 options.content_all_charsets,
592 content_all_charsets_label);
593 widget_disable (content_all_charsets_cbox->widget, disable);
594 add_widget (find_dlg, content_all_charsets_cbox);
595 #endif
597 content_case_sens_cbox =
598 check_new (cbox_position--, FIND_X / 2 + 1, options.content_case_sens, content_case_label);
599 widget_disable (content_case_sens_cbox->widget, disable);
600 add_widget (find_dlg, content_case_sens_cbox);
602 content_regexp_cbox =
603 check_new (cbox_position--, FIND_X / 2 + 1, options.content_regexp, content_regexp_label);
604 widget_disable (content_regexp_cbox->widget, disable);
605 add_widget (find_dlg, content_regexp_cbox);
607 cbox_position = FIND_Y - 6;
609 skip_hidden_cbox = check_new (cbox_position--, 3, options.skip_hidden, file_skip_hidden_label);
610 add_widget (find_dlg, skip_hidden_cbox);
612 #ifdef HAVE_CHARSET
613 file_all_charsets_cbox =
614 check_new (cbox_position--, 3, options.file_all_charsets, file_all_charsets_label);
615 add_widget (find_dlg, file_all_charsets_cbox);
616 #endif
618 file_case_sens_cbox = check_new (cbox_position--, 3, options.file_case_sens, file_case_label);
619 add_widget (find_dlg, file_case_sens_cbox);
621 file_pattern_cbox = check_new (cbox_position--, 3, options.file_pattern, file_pattern_label);
622 add_widget (find_dlg, file_pattern_cbox);
624 recursively_cbox = check_new (cbox_position, 3, options.find_recurs, file_recurs_label);
625 add_widget (find_dlg, recursively_cbox);
627 /* This checkbox is located in the second column */
628 content_use_cbox =
629 check_new (cbox_position, FIND_X / 2 + 1, options.content_use, content_use_label);
630 add_widget (find_dlg, content_use_cbox);
632 in_with =
633 input_new (8, FIND_X / 2 + 1, input_get_default_colors (), FIND_X / 2 - 4, INPUT_LAST_TEXT,
634 MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_DEFAULT);
635 widget_disable (in_with->widget, disable);
636 add_widget (find_dlg, in_with);
638 content_label = label_new (7, FIND_X / 2 + 1, _("Content:"));
639 widget_disable (content_label->widget, disable);
640 add_widget (find_dlg, content_label);
642 in_name = input_new (8, 3, input_get_default_colors (),
643 FIND_X / 2 - 4, INPUT_LAST_TEXT, "name", INPUT_COMPLETE_DEFAULT);
644 add_widget (find_dlg, in_name);
645 add_widget (find_dlg, label_new (7, 3, _("File name:")));
647 in_ignore = input_new (5, 3, input_get_default_colors (), FIND_X - 6,
648 options.ignore_dirs != NULL ? options.ignore_dirs : "",
649 "ignoredirs", INPUT_COMPLETE_DEFAULT);
650 widget_disable (in_ignore->widget, !options.ignore_dirs_enable);
651 add_widget (find_dlg, in_ignore);
653 ignore_dirs_cbox =
654 check_new (4, 3, options.ignore_dirs_enable, _("Ena&ble ignore directories:"));
655 add_widget (find_dlg, ignore_dirs_cbox);
657 add_widget (find_dlg, button_new (3, FIND_X - b2 - 2, B_TREE, NORMAL_BUTTON, buts[2], 0));
659 in_start = input_new (3, 3, input_get_default_colors (),
660 FIND_X - b2 - 6, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
661 add_widget (find_dlg, in_start);
662 add_widget (find_dlg, label_new (2, 3, _("Start at:")));
664 find_par_start:
665 dlg_select_widget (in_name);
667 switch (run_dlg (find_dlg))
669 case B_CANCEL:
670 return_value = FALSE;
671 break;
673 case B_TREE:
675 const char *temp_dir = in_start->buffer;
677 if ((temp_dir[0] == '\0') || ((temp_dir[0] == '.') && (temp_dir[1] == '\0')))
678 temp_dir = current_panel->cwd;
680 if (in_start_dir != INPUT_LAST_TEXT)
681 g_free (in_start_dir);
682 in_start_dir = tree_box (temp_dir);
683 if (in_start_dir == NULL)
684 in_start_dir = g_strdup (temp_dir);
686 input_assign_text (in_start, in_start_dir);
688 /* Warning: Dreadful goto */
689 goto find_par_start;
692 default:
694 char *s;
696 #ifdef HAVE_CHARSET
697 options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
698 options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
699 #endif
700 options.content_use = content_use_cbox->state & C_BOOL;
701 options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
702 options.content_regexp = content_regexp_cbox->state & C_BOOL;
703 options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
704 options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
705 options.find_recurs = recursively_cbox->state & C_BOOL;
706 options.file_pattern = file_pattern_cbox->state & C_BOOL;
707 options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
708 options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
709 options.ignore_dirs_enable = ignore_dirs_cbox->state & C_BOOL;
710 g_free (options.ignore_dirs);
711 options.ignore_dirs = g_strdup (in_ignore->buffer);
713 *content = (options.content_use && in_with->buffer[0] != '\0')
714 ? g_strdup (in_with->buffer) : NULL;
715 *start_dir = in_start->buffer[0] != '\0' ? in_start->buffer : (char *) ".";
716 *pattern = g_strdup (in_name->buffer);
717 if (in_start_dir != INPUT_LAST_TEXT)
718 g_free (in_start_dir);
719 in_start_dir = g_strdup (*start_dir);
721 s = tilde_expand (*start_dir);
722 canonicalize_pathname (s);
724 if (s[0] == '.' && s[1] == '\0')
726 *start_dir = g_strdup (current_panel->cwd);
727 /* FIXME: is current_panel->cwd canonicalized? */
728 /* relative paths will be used in panelization */
729 *start_dir_len = (ssize_t) strlen (current_panel->cwd);
730 g_free (s);
732 else if (g_path_is_absolute (s))
734 *start_dir = s;
735 *start_dir_len = -1;
737 else
739 /* relative paths will be used in panelization */
740 *start_dir = mc_build_filename (current_panel->cwd, s, (char *) NULL);
741 *start_dir_len = (ssize_t) strlen (current_panel->cwd);
742 g_free (s);
745 if (!options.ignore_dirs_enable || in_ignore->buffer[0] == '\0'
746 || (in_ignore->buffer[0] == '.' && in_ignore->buffer[1] == '\0'))
747 *ignore_dirs = NULL;
748 else
749 *ignore_dirs = g_strdup (in_ignore->buffer);
751 find_save_options ();
753 return_value = TRUE;
757 destroy_dlg (find_dlg);
759 return return_value;
762 /* --------------------------------------------------------------------------------------------- */
764 #if GLIB_CHECK_VERSION (2, 14, 0)
765 static inline void
766 push_directory (const char *dir)
768 g_queue_push_head (&dir_queue, (void *) dir);
771 /* --------------------------------------------------------------------------------------------- */
773 static inline char *
774 pop_directory (void)
776 return (char *) g_queue_pop_tail (&dir_queue);
779 /* --------------------------------------------------------------------------------------------- */
780 /** Remove all the items from the stack */
782 static void
783 clear_stack (void)
785 g_queue_foreach (&dir_queue, (GFunc) g_free, NULL);
786 g_queue_clear (&dir_queue);
789 /* --------------------------------------------------------------------------------------------- */
791 #else /* GLIB_CHECK_VERSION */
792 static void
793 push_directory (const char *dir)
795 dir_stack *new;
797 new = g_new (dir_stack, 1);
798 new->name = (char *) dir;
799 new->prev = dir_stack_base;
800 dir_stack_base = new;
803 /* --------------------------------------------------------------------------------------------- */
805 static char *
806 pop_directory (void)
808 char *name = NULL;
810 if (dir_stack_base != NULL)
812 dir_stack *next;
813 name = dir_stack_base->name;
814 next = dir_stack_base->prev;
815 g_free (dir_stack_base);
816 dir_stack_base = next;
819 return name;
822 /* --------------------------------------------------------------------------------------------- */
823 /** Remove all the items from the stack */
825 static void
826 clear_stack (void)
828 char *dir = NULL;
829 while ((dir = pop_directory ()) != NULL)
830 g_free (dir);
832 #endif /* GLIB_CHECK_VERSION */
834 /* --------------------------------------------------------------------------------------------- */
836 static void
837 insert_file (const char *dir, const char *file)
839 char *tmp_name = NULL;
840 static char *dirname = NULL;
842 while (dir[0] == PATH_SEP && dir[1] == PATH_SEP)
843 dir++;
845 if (old_dir)
847 if (strcmp (old_dir, dir))
849 g_free (old_dir);
850 old_dir = g_strdup (dir);
851 dirname = add_to_list (dir, NULL);
854 else
856 old_dir = g_strdup (dir);
857 dirname = add_to_list (dir, NULL);
860 tmp_name = g_strdup_printf (" %s", file);
861 add_to_list (tmp_name, dirname);
862 g_free (tmp_name);
865 /* --------------------------------------------------------------------------------------------- */
867 static void
868 find_add_match (const char *dir, const char *file)
870 insert_file (dir, file);
872 /* Don't scroll */
873 if (matches == 0)
874 listbox_select_first (find_list);
875 send_message (&find_list->widget, WIDGET_DRAW, 0);
877 matches++;
878 found_num_update ();
881 /* --------------------------------------------------------------------------------------------- */
883 * get_line_at:
885 * Returns malloced null-terminated line from file file_fd.
886 * Input is buffered in buf_size long buffer.
887 * Current pos in buf is stored in pos.
888 * n_read - number of read chars.
889 * has_newline - is there newline ?
892 static char *
893 get_line_at (int file_fd, char *buf, int buf_size, int *pos, int *n_read, gboolean * has_newline)
895 char *buffer = NULL;
896 int buffer_size = 0;
897 char ch = 0;
898 int i = 0;
900 for (;;)
902 if (*pos >= *n_read)
904 *pos = 0;
905 *n_read = mc_read (file_fd, buf, buf_size);
906 if (*n_read <= 0)
907 break;
910 ch = buf[(*pos)++];
911 if (ch == '\0')
913 /* skip possible leading zero(s) */
914 if (i == 0)
915 continue;
916 break;
919 if (i >= buffer_size - 1)
920 buffer = g_realloc (buffer, buffer_size += 80);
922 /* Strip newline */
923 if (ch == '\n')
924 break;
926 buffer[i++] = ch;
929 *has_newline = (ch != '\0');
931 if (buffer != NULL)
932 buffer[i] = '\0';
934 return buffer;
937 /* --------------------------------------------------------------------------------------------- */
939 static FindProgressStatus
940 check_find_events (Dlg_head * h)
942 Gpm_Event event;
943 int c;
945 event.x = -1;
946 c = tty_get_event (&event, h->mouse_status == MOU_REPEAT, FALSE);
947 if (c != EV_NONE)
949 dlg_process_event (h, c, &event);
950 if (h->ret_value == B_ENTER
951 || h->ret_value == B_CANCEL || h->ret_value == B_AGAIN || h->ret_value == B_PANELIZE)
953 /* dialog terminated */
954 return FIND_ABORT;
956 if (!(h->flags & DLG_WANT_IDLE))
958 /* searching suspended */
959 return FIND_SUSPEND;
963 return FIND_CONT;
966 /* --------------------------------------------------------------------------------------------- */
968 * search_content:
970 * Search the content_pattern string in the DIRECTORY/FILE.
971 * It will add the found entries to the find listbox.
973 * returns FALSE if do_search should look for another file
974 * TRUE if do_search should exit and proceed to the event handler
977 static gboolean
978 search_content (Dlg_head * h, const char *directory, const char *filename)
980 struct stat s;
981 char buffer[BUF_4K];
982 char *fname = NULL;
983 int file_fd;
984 gboolean ret_val = FALSE;
986 fname = mc_build_filename (directory, filename, (char *) NULL);
988 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode))
990 g_free (fname);
991 return FALSE;
994 file_fd = mc_open (fname, O_RDONLY);
995 g_free (fname);
997 if (file_fd == -1)
998 return FALSE;
1000 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), str_trunc (filename, FIND2_X_USE));
1002 status_update (buffer);
1003 mc_refresh ();
1005 tty_enable_interrupt_key ();
1006 tty_got_interrupt ();
1009 int line = 1;
1010 int pos = 0;
1011 int n_read = 0;
1012 gboolean has_newline;
1013 char *p = NULL;
1014 gboolean found = FALSE;
1015 gsize found_len;
1016 char result[BUF_MEDIUM];
1018 if (resuming)
1020 /* We've been previously suspended, start from the previous position */
1021 resuming = 0;
1022 line = last_line;
1023 pos = last_pos;
1025 while (!ret_val
1026 && (p = get_line_at (file_fd, buffer, sizeof (buffer),
1027 &pos, &n_read, &has_newline)) != NULL)
1029 if (!found /* Search in binary line once */
1030 && mc_search_run (search_content_handle,
1031 (const void *) p, 0, strlen (p), &found_len))
1033 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
1034 find_add_match (directory, result);
1035 found = TRUE;
1037 g_free (p);
1039 if (found && options.content_first_hit)
1040 break;
1042 if (has_newline)
1044 found = FALSE;
1045 line++;
1048 if ((line & 0xff) == 0)
1050 FindProgressStatus res;
1051 res = check_find_events (h);
1052 switch (res)
1054 case FIND_ABORT:
1055 stop_idle (h);
1056 ret_val = TRUE;
1057 break;
1058 case FIND_SUSPEND:
1059 resuming = 1;
1060 last_line = line;
1061 last_pos = pos;
1062 ret_val = TRUE;
1063 break;
1064 default:
1065 break;
1070 tty_disable_interrupt_key ();
1071 mc_close (file_fd);
1072 return ret_val;
1075 /* --------------------------------------------------------------------------------------------- */
1078 If dir is absolute, this means we're within dir and searching file here.
1079 If dir is relative, this means we're going to add dir to the directory stack.
1081 static gboolean
1082 find_ignore_dir_search (const char *dir)
1084 if (find_ignore_dirs != NULL)
1086 const size_t dlen = strlen (dir);
1087 const unsigned char dabs = g_path_is_absolute (dir) ? 1 : 0;
1089 char **ignore_dir;
1091 for (ignore_dir = find_ignore_dirs; *ignore_dir != NULL; ignore_dir++)
1093 const size_t ilen = strlen (*ignore_dir);
1094 const unsigned char iabs = g_path_is_absolute (*ignore_dir) ? 2 : 0;
1096 /* ignore dir is too long -- skip it */
1097 if (dlen < ilen)
1098 continue;
1100 /* handle absolute and relative paths */
1101 switch (iabs | dabs)
1103 case 0: /* both paths are relative */
1104 case 3: /* both paths are abolute */
1105 /* if ignore dir is not a path of dir -- skip it */
1106 if (strncmp (dir, *ignore_dir, ilen) == 0)
1108 /* be sure that ignore dir is not a part of dir like:
1109 ignore dir is "h", dir is "home" */
1110 if (dir[ilen] == '\0' || dir[ilen] == PATH_SEP)
1111 return TRUE;
1113 break;
1114 case 1: /* dir is absolute, ignore_dir is relative */
1116 char *d;
1118 d = strstr (dir, *ignore_dir);
1119 if (d != NULL && d[-1] == PATH_SEP && (d[ilen] == '\0' || d[ilen] == PATH_SEP))
1120 return TRUE;
1122 break;
1123 case 2: /* dir is relative, ignore_dir is absolute */
1124 /* FIXME: skip this case */
1125 break;
1126 default: /* this cannot occurs */
1127 return FALSE;
1132 return FALSE;
1135 /* --------------------------------------------------------------------------------------------- */
1137 static void
1138 find_rotate_dash (const Dlg_head * h, gboolean finish)
1140 static const char rotating_dash[] = "|/-\\";
1141 static unsigned int pos = 0;
1143 if (verbose)
1145 pos = (pos + 1) % 4;
1146 tty_setcolor (h->color[DLG_COLOR_NORMAL]);
1147 dlg_move (h, FIND2_Y - 7, FIND2_X - 4);
1148 tty_print_char (finish ? ' ' : rotating_dash[pos]);
1149 mc_refresh ();
1153 /* --------------------------------------------------------------------------------------------- */
1155 static int
1156 do_search (Dlg_head * h)
1158 static struct dirent *dp = NULL;
1159 static DIR *dirp = NULL;
1160 static char *directory = NULL;
1161 struct stat tmp_stat;
1162 static int subdirs_left = 0;
1163 gsize bytes_found;
1164 unsigned short count;
1166 if (h == NULL)
1167 { /* someone forces me to close dirp */
1168 if (dirp != NULL)
1170 mc_closedir (dirp);
1171 dirp = NULL;
1173 g_free (directory);
1174 directory = NULL;
1175 dp = NULL;
1176 return 1;
1179 for (count = 0; count < 32; count++)
1181 while (dp == NULL)
1183 if (dirp != NULL)
1185 mc_closedir (dirp);
1186 dirp = NULL;
1189 while (dirp == NULL)
1191 char *tmp = NULL;
1193 tty_setcolor (REVERSE_COLOR);
1195 while (TRUE)
1197 tmp = pop_directory ();
1198 if (tmp == NULL)
1200 running = FALSE;
1201 if (ignore_count == 0)
1202 status_update (_("Finished"));
1203 else
1205 char msg[BUF_SMALL];
1206 g_snprintf (msg, sizeof (msg),
1207 ngettext ("Finished (ignored %zd directory)",
1208 "Finished (ignored %zd directories)",
1209 ignore_count), ignore_count);
1210 status_update (msg);
1212 find_rotate_dash (h, TRUE);
1213 stop_idle (h);
1214 return 0;
1217 /* handle absolute ignore dirs here */
1218 if (!find_ignore_dir_search (tmp))
1219 break;
1221 g_free (tmp);
1222 ignore_count++;
1225 g_free (directory);
1226 directory = tmp;
1228 if (verbose)
1230 char buffer[BUF_SMALL];
1232 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
1233 str_trunc (directory, FIND2_X_USE));
1234 status_update (buffer);
1236 /* mc_stat should not be called after mc_opendir
1237 because vfs_s_opendir modifies the st_nlink
1239 if (mc_stat (directory, &tmp_stat) == 0)
1240 subdirs_left = tmp_stat.st_nlink - 2;
1241 else
1242 subdirs_left = 0;
1244 dirp = mc_opendir (directory);
1245 } /* while (!dirp) */
1247 /* skip invalid filenames */
1248 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1250 } /* while (!dp) */
1252 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
1254 /* skip invalid filenames */
1255 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1258 return 1;
1261 if (!(options.skip_hidden && (dp->d_name[0] == '.')))
1263 gboolean search_ok;
1265 if ((subdirs_left != 0) && options.find_recurs && (directory != NULL))
1266 { /* Can directory be NULL ? */
1267 /* handle relative ignore dirs here */
1268 if (options.ignore_dirs_enable && find_ignore_dir_search (dp->d_name))
1269 ignore_count++;
1270 else
1272 char *tmp_name;
1274 tmp_name = mc_build_filename (directory, dp->d_name, (char *) NULL);
1276 if (mc_lstat (tmp_name, &tmp_stat) == 0 && S_ISDIR (tmp_stat.st_mode))
1278 push_directory (tmp_name);
1279 subdirs_left--;
1281 else
1282 g_free (tmp_name);
1286 search_ok = mc_search_run (search_file_handle, dp->d_name,
1287 0, strlen (dp->d_name), &bytes_found);
1289 if (search_ok)
1291 if (content_pattern == NULL)
1292 find_add_match (directory, dp->d_name);
1293 else if (search_content (h, directory, dp->d_name))
1294 return 1;
1298 /* skip invalid filenames */
1299 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1301 } /* for */
1303 find_rotate_dash (h, FALSE);
1305 return 1;
1308 /* --------------------------------------------------------------------------------------------- */
1310 static void
1311 init_find_vars (void)
1313 g_free (old_dir);
1314 old_dir = NULL;
1315 matches = 0;
1316 ignore_count = 0;
1318 /* Remove all the items from the stack */
1319 clear_stack ();
1321 g_strfreev (find_ignore_dirs);
1322 find_ignore_dirs = NULL;
1325 /* --------------------------------------------------------------------------------------------- */
1327 static void
1328 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
1330 char *fullname = NULL;
1331 const char *filename = NULL;
1332 int line;
1334 if (content_pattern != NULL)
1336 filename = strchr (file + 4, ':') + 1;
1337 line = atoi (file + 4);
1339 else
1341 filename = file + 4;
1342 line = 0;
1345 fullname = mc_build_filename (dir, filename, (char *) NULL);
1346 if (edit)
1347 do_edit_at_line (fullname, use_internal_edit, line);
1348 else
1349 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
1350 g_free (fullname);
1353 /* --------------------------------------------------------------------------------------------- */
1355 static cb_ret_t
1356 view_edit_currently_selected_file (int unparsed_view, int edit)
1358 char *dir = NULL;
1359 char *text = NULL;
1361 listbox_get_current (find_list, &text, (void **) &dir);
1363 if ((text == NULL) || (dir == NULL))
1364 return MSG_NOT_HANDLED;
1366 find_do_view_edit (unparsed_view, edit, dir, text);
1367 return MSG_HANDLED;
1370 /* --------------------------------------------------------------------------------------------- */
1372 static cb_ret_t
1373 find_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
1375 switch (msg)
1377 case DLG_KEY:
1378 if (parm == KEY_F (3) || parm == KEY_F (13))
1380 int unparsed_view = (parm == KEY_F (13));
1381 return view_edit_currently_selected_file (unparsed_view, 0);
1383 if (parm == KEY_F (4))
1385 return view_edit_currently_selected_file (0, 1);
1387 return MSG_NOT_HANDLED;
1389 case DLG_IDLE:
1390 do_search (h);
1391 return MSG_HANDLED;
1393 default:
1394 return default_dlg_callback (h, sender, msg, parm, data);
1398 /* --------------------------------------------------------------------------------------------- */
1399 /** Handles the Stop/Start button in the find window */
1401 static int
1402 start_stop (WButton * button, int action)
1404 (void) button;
1405 (void) action;
1407 running = is_start;
1408 set_idle_proc (find_dlg, running);
1409 is_start = !is_start;
1411 status_update (is_start ? _("Stopped") : _("Searching"));
1412 button_set_text (stop_button, fbuts[is_start ? 1 : 0].text);
1414 return 0;
1417 /* --------------------------------------------------------------------------------------------- */
1418 /** Handle view command, when invoked as a button */
1420 static int
1421 find_do_view_file (WButton * button, int action)
1423 (void) button;
1424 (void) action;
1426 view_edit_currently_selected_file (0, 0);
1427 return 0;
1430 /* --------------------------------------------------------------------------------------------- */
1431 /** Handle edit command, when invoked as a button */
1433 static int
1434 find_do_edit_file (WButton * button, int action)
1436 (void) button;
1437 (void) action;
1439 view_edit_currently_selected_file (0, 1);
1440 return 0;
1443 /* --------------------------------------------------------------------------------------------- */
1445 static void
1446 setup_gui (void)
1448 #ifdef ENABLE_NLS
1449 static gboolean i18n_flag = FALSE;
1451 if (!i18n_flag)
1453 int i = sizeof (fbuts) / sizeof (fbuts[0]);
1454 while (i-- != 0)
1456 fbuts[i].text = _(fbuts[i].text);
1457 fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1460 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
1461 i18n_flag = TRUE;
1463 #endif /* ENABLE_NLS */
1466 * Dynamically place buttons centered within current window size
1469 int l0 = max (fbuts[0].len, fbuts[1].len);
1470 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
1471 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
1472 int r1, r2;
1474 /* Check, if both button rows fit within FIND2_X */
1475 FIND2_X = max (l1 + 9, COLS - 16);
1476 FIND2_X = max (l2 + 8, FIND2_X);
1478 /* compute amount of space between buttons for each row */
1479 r1 = (FIND2_X - 4 - l1) % 5;
1480 l1 = (FIND2_X - 4 - l1) / 5;
1481 r2 = (FIND2_X - 4 - l2) % 4;
1482 l2 = (FIND2_X - 4 - l2) / 4;
1484 /* ...and finally, place buttons */
1485 fbuts[2].x = 2 + r1 / 2 + l1;
1486 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
1487 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
1488 fbuts[4].x = fbuts[0].x + l0 + l1;
1489 fbuts[5].x = 2 + r2 / 2 + l2;
1490 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
1491 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
1494 find_dlg =
1495 create_dlg (TRUE, 0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
1496 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
1498 add_widget (find_dlg,
1499 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
1500 fbuts[7].text, find_do_edit_file));
1501 add_widget (find_dlg,
1502 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
1503 fbuts[6].text, find_do_view_file));
1504 add_widget (find_dlg,
1505 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON, fbuts[5].text,
1506 NULL));
1508 add_widget (find_dlg,
1509 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON, fbuts[4].text, NULL));
1510 stop_button =
1511 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON, fbuts[0].text, start_stop);
1512 add_widget (find_dlg, stop_button);
1513 add_widget (find_dlg,
1514 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON, fbuts[3].text, NULL));
1515 add_widget (find_dlg,
1516 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON, fbuts[2].text, NULL));
1518 status_label = label_new (FIND2_Y - 7, 4, _("Searching"));
1519 add_widget (find_dlg, status_label);
1521 found_num_label = label_new (FIND2_Y - 6, 4, "");
1522 add_widget (find_dlg, found_num_label);
1524 find_list = listbox_new (2, 2, FIND2_Y - 10, FIND2_X - 4, FALSE, NULL);
1525 add_widget (find_dlg, find_list);
1528 /* --------------------------------------------------------------------------------------------- */
1530 static int
1531 run_process (void)
1533 int ret;
1535 search_content_handle = mc_search_new (content_pattern, -1);
1536 if (search_content_handle)
1538 search_content_handle->search_type =
1539 options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
1540 search_content_handle->is_case_sensitive = options.content_case_sens;
1541 search_content_handle->whole_words = options.content_whole_words;
1542 search_content_handle->is_all_charsets = options.content_all_charsets;
1544 search_file_handle = mc_search_new (find_pattern, -1);
1545 search_file_handle->search_type = options.file_pattern ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
1546 search_file_handle->is_case_sensitive = options.file_case_sens;
1547 search_file_handle->is_all_charsets = options.file_all_charsets;
1548 search_file_handle->is_entire_line = options.file_pattern;
1550 resuming = 0;
1552 set_idle_proc (find_dlg, 1);
1553 ret = run_dlg (find_dlg);
1555 mc_search_free (search_file_handle);
1556 search_file_handle = NULL;
1557 mc_search_free (search_content_handle);
1558 search_content_handle = NULL;
1560 return ret;
1563 /* --------------------------------------------------------------------------------------------- */
1565 static void
1566 kill_gui (void)
1568 set_idle_proc (find_dlg, 0);
1569 destroy_dlg (find_dlg);
1572 /* --------------------------------------------------------------------------------------------- */
1574 static int
1575 do_find (const char *start_dir, ssize_t start_dir_len, const char *ignore_dirs,
1576 const char *pattern, const char *content, char **dirname, char **filename)
1578 int return_value = 0;
1579 char *dir_tmp = NULL, *file_tmp = NULL;
1581 setup_gui ();
1583 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1584 find_pattern = (char *) pattern;
1586 content_pattern = NULL;
1587 if (options.content_use && content != NULL && str_is_valid_string (content))
1588 content_pattern = g_strdup (content);
1590 init_find_vars ();
1591 parse_ignore_dirs (ignore_dirs);
1592 push_directory (start_dir);
1594 return_value = run_process ();
1596 /* Clear variables */
1597 init_find_vars ();
1599 get_list_info (&file_tmp, &dir_tmp);
1601 if (dir_tmp)
1602 *dirname = g_strdup (dir_tmp);
1603 if (file_tmp)
1604 *filename = g_strdup (file_tmp);
1606 if (return_value == B_PANELIZE && *filename)
1608 int status, link_to_dir, stale_link;
1609 int next_free = 0;
1610 int i;
1611 struct stat st;
1612 GList *entry;
1613 dir_list *list = &current_panel->dir;
1614 char *name = NULL;
1616 if (set_zero_dir (list))
1617 next_free++;
1619 for (i = 0, entry = find_list->list; entry != NULL; i++, entry = g_list_next (entry))
1621 const char *lc_filename = NULL;
1622 WLEntry *le = (WLEntry *) entry->data;
1623 char *p;
1625 if ((le->text == NULL) || (le->data == NULL))
1626 continue;
1628 if (content_pattern != NULL)
1629 lc_filename = strchr (le->text + 4, ':') + 1;
1630 else
1631 lc_filename = le->text + 4;
1633 name = mc_build_filename (le->data, lc_filename, (char *) NULL);
1634 /* skip initial start dir */
1635 if (start_dir_len < 0)
1636 p = name;
1637 else
1639 p = name + (size_t) start_dir_len;
1640 if (*p == PATH_SEP)
1641 p++;
1644 status = handle_path (list, p, &st, next_free, &link_to_dir, &stale_link);
1645 if (status == 0)
1647 g_free (name);
1648 continue;
1650 if (status == -1)
1652 g_free (name);
1653 break;
1656 /* don't add files more than once to the panel */
1657 if (content_pattern != NULL && next_free > 0
1658 && strcmp (list->list[next_free - 1].fname, p) == 0)
1660 g_free (name);
1661 continue;
1664 if (next_free == 0) /* first turn i.e clean old list */
1665 panel_clean_dir (current_panel);
1666 list->list[next_free].fnamelen = strlen (p);
1667 list->list[next_free].fname = g_strndup (p, list->list[next_free].fnamelen);
1668 list->list[next_free].f.marked = 0;
1669 list->list[next_free].f.link_to_dir = link_to_dir;
1670 list->list[next_free].f.stale_link = stale_link;
1671 list->list[next_free].f.dir_size_computed = 0;
1672 list->list[next_free].st = st;
1673 list->list[next_free].sort_key = NULL;
1674 list->list[next_free].second_sort_key = NULL;
1675 next_free++;
1676 g_free (name);
1677 if (!(next_free & 15))
1678 rotate_dash ();
1681 if (next_free)
1683 current_panel->count = next_free;
1684 current_panel->is_panelized = TRUE;
1686 /* absolute path */
1687 if (start_dir_len < 0)
1689 int ret;
1691 strcpy (current_panel->cwd, PATH_SEP_STR);
1692 ret = chdir (PATH_SEP_STR);
1694 panelize_save_panel (current_panel);
1698 g_free (content_pattern);
1699 kill_gui ();
1700 do_search (NULL); /* force do_search to release resources */
1701 g_free (old_dir);
1702 old_dir = NULL;
1704 return return_value;
1707 /* --------------------------------------------------------------------------------------------- */
1708 /*** public functions ****************************************************************************/
1709 /* --------------------------------------------------------------------------------------------- */
1711 void
1712 find_file (void)
1714 char *start_dir = NULL, *pattern = NULL, *content = NULL, *ignore_dirs = NULL;
1715 ssize_t start_dir_len;
1716 char *filename = NULL, *dirname = NULL;
1717 int v;
1719 while (find_parameters (&start_dir, &start_dir_len, &ignore_dirs, &pattern, &content))
1721 if (pattern[0] == '\0')
1722 break; /* nothing search */
1724 dirname = filename = NULL;
1725 is_start = FALSE;
1726 v = do_find (start_dir, start_dir_len, ignore_dirs, pattern, content, &dirname, &filename);
1727 g_free (ignore_dirs);
1728 g_free (pattern);
1730 if (v == B_ENTER)
1732 if (dirname != NULL)
1734 do_cd (dirname, cd_exact);
1735 if (filename != NULL)
1736 try_to_select (current_panel,
1737 filename + (content != NULL
1738 ? strchr (filename + 4, ':') - filename + 1 : 4));
1740 else if (filename != NULL)
1741 do_cd (filename, cd_exact);
1743 g_free (dirname);
1744 g_free (filename);
1745 break;
1748 g_free (content);
1749 g_free (dirname);
1750 g_free (filename);
1752 if (v == B_CANCEL)
1753 break;
1755 if (v == B_PANELIZE)
1757 panel_re_sort (current_panel);
1758 try_to_select (current_panel, NULL);
1759 break;
1764 /* --------------------------------------------------------------------------------------------- */