Added two macro examples:
[zuwinko.git] / src / filemanager / find.c
blob1cba493cb3cc42997500da9bd120e3bf9a0eb351
1 /* Find file command for the Midnight Commander
2 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
4 Written 1995 by Miguel de Icaza
6 Complete rewrite.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 /** \file find.c
23 * \brief Source: Find file command
26 #include <config.h>
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <sys/stat.h>
35 #include "lib/global.h"
37 #include "lib/tty/tty.h"
38 #include "lib/tty/key.h"
39 #include "lib/skin.h"
40 #include "lib/search.h"
41 #include "lib/mcconfig.h"
42 #include "lib/strutil.h"
43 #include "lib/widget.h"
44 #include "lib/vfs/mc-vfs/vfs.h"
45 #include "lib/util.h" /* canonicalize_pathname() */
47 #include "src/setup.h" /* verbose */
48 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
49 #include "src/main.h" /* do_cd */
51 #include "dir.h"
52 #include "cmd.h" /* view_file_at_line */
53 #include "midnight.h" /* current_panel */
54 #include "boxes.h"
55 #include "layout.h" /* mc_refresh() */
57 #include "find.h"
59 /*** global variables ****************************************************************************/
61 /*** file scope macro definitions ****************************************************************/
63 /* Size of the find window */
64 #define FIND2_Y (LINES - 4)
66 #define FIND2_X_USE (FIND2_X - 20)
68 /*** file scope type declarations ****************************************************************/
70 /* A couple of extra messages we need */
71 enum
73 B_STOP = B_USER + 1,
74 B_AGAIN,
75 B_PANELIZE,
76 B_TREE,
77 B_VIEW
80 typedef enum
82 FIND_CONT = 0,
83 FIND_SUSPEND,
84 FIND_ABORT
85 } FindProgressStatus;
87 /* find file options */
88 typedef struct
90 /* file name options */
91 gboolean file_case_sens;
92 gboolean file_pattern;
93 gboolean find_recurs;
94 gboolean skip_hidden;
95 gboolean file_all_charsets;
97 /* file content options */
98 gboolean content_use;
99 gboolean content_case_sens;
100 gboolean content_regexp;
101 gboolean content_first_hit;
102 gboolean content_whole_words;
103 gboolean content_all_charsets;
105 /* whether use ignore dirs or not */
106 gboolean ignore_dirs_enable;
107 /* list of directories to be ignored, separated by ':' */
108 char *ignore_dirs;
109 } find_file_options_t;
111 /*** file scope variables ************************************************************************/
113 /* Parsed ignore dirs */
114 static char **find_ignore_dirs = NULL;
116 /* Size of the find parameters window */
117 #if HAVE_CHARSET
118 static int FIND_Y = 19;
119 #else
120 static int FIND_Y = 18;
121 #endif
122 static int FIND_X = 68;
124 static int FIND2_X = 64;
126 /* static variables to remember find parameters */
127 static WInput *in_start; /* Start path */
128 static WInput *in_name; /* Filename */
129 static WInput *in_with; /* Text */
130 static WInput *in_ignore;
131 static WLabel *content_label; /* 'Content:' label */
132 static WCheck *file_case_sens_cbox; /* "case sensitive" checkbox */
133 static WCheck *file_pattern_cbox; /* File name is glob or regexp */
134 static WCheck *recursively_cbox;
135 static WCheck *skip_hidden_cbox;
136 static WCheck *content_use_cbox; /* Take into account the Content field */
137 static WCheck *content_case_sens_cbox; /* "case sensitive" checkbox */
138 static WCheck *content_regexp_cbox; /* "find regular expression" checkbox */
139 static WCheck *content_first_hit_cbox; /* "First hit" checkbox" */
140 static WCheck *content_whole_words_cbox; /* "whole words" checkbox */
141 #ifdef HAVE_CHARSET
142 static WCheck *file_all_charsets_cbox;
143 static WCheck *content_all_charsets_cbox;
144 #endif
145 static WCheck *ignore_dirs_cbox;
147 static gboolean running = FALSE; /* nice flag */
148 static char *find_pattern = NULL; /* Pattern to search */
149 static char *content_pattern = NULL; /* pattern to search inside files; if
150 content_regexp_flag is true, it contains the
151 regex pattern, else the search string. */
152 static unsigned long matches; /* Number of matches */
153 static gboolean is_start = FALSE; /* Status of the start/stop toggle button */
154 static char *old_dir = NULL;
156 /* Where did we stop */
157 static int resuming;
158 static int last_line;
159 static int last_pos;
161 static size_t ignore_count = 0;
163 static Dlg_head *find_dlg; /* The dialog */
164 static WButton *stop_button; /* pointer to the stop button */
165 static WLabel *status_label; /* Finished, Searching etc. */
166 static WLabel *found_num_label; /* Number of found items */
167 static WListbox *find_list; /* Listbox with the file list */
169 /* This keeps track of the directory stack */
170 #if GLIB_CHECK_VERSION (2, 14, 0)
171 static GQueue dir_queue = G_QUEUE_INIT;
172 #else
173 typedef struct dir_stack
175 char *name;
176 struct dir_stack *prev;
177 } dir_stack;
179 static dir_stack *dir_stack_base = 0;
180 #endif /* GLIB_CHECK_VERSION */
182 /* *INDENT-OFF* */
183 static struct
185 const char *text;
186 int len; /* length including space and brackets */
187 int x;
188 } fbuts[] =
190 {N_("&Suspend"), 11, 29},
191 {N_("Con&tinue"), 12, 29},
192 {N_("&Chdir"), 11, 3},
193 {N_("&Again"), 9, 17},
194 {N_("&Quit"), 8, 43},
195 {N_("Pane&lize"), 12, 3},
196 {N_("&View - F3"), 13, 20},
197 {N_("&Edit - F4"), 13, 38}
199 /* *INDENT-ON* */
201 static find_file_options_t options = {
202 TRUE, TRUE, TRUE, FALSE, FALSE,
203 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE
206 static char *in_start_dir = INPUT_LAST_TEXT;
208 static mc_search_t *search_file_handle = NULL;
209 static mc_search_t *search_content_handle = NULL;
211 /*** file scope functions ************************************************************************/
213 static void
214 parse_ignore_dirs (const char *ignore_dirs)
216 size_t r = 0, w = 0; /* read and write iterators */
218 if (!options.ignore_dirs_enable || ignore_dirs == NULL || ignore_dirs[0] == '\0')
219 return;
221 find_ignore_dirs = g_strsplit (ignore_dirs, ":", -1);
223 /* Values like '/foo::/bar: produce holes in list.
224 * Find and remove them */
225 for (; find_ignore_dirs[r] != NULL; r++)
227 if (find_ignore_dirs[r][0] == '\0')
229 /* empty entry -- skip it */
230 g_free (find_ignore_dirs[r]);
231 find_ignore_dirs[r] = NULL;
232 continue;
235 if (r != w)
237 /* copy entry to the previous free array cell */
238 find_ignore_dirs[w] = find_ignore_dirs[r];
239 find_ignore_dirs[r] = NULL;
242 canonicalize_pathname (find_ignore_dirs[w]);
243 if (find_ignore_dirs[w][0] != '\0')
244 w++;
245 else
247 g_free (find_ignore_dirs[w]);
248 find_ignore_dirs[w] = NULL;
252 if (find_ignore_dirs[0] == NULL)
254 g_strfreev (find_ignore_dirs);
255 find_ignore_dirs = NULL;
259 /* --------------------------------------------------------------------------------------------- */
261 static void
262 find_load_options (void)
264 static gboolean loaded = FALSE;
265 char *ignore_dirs;
267 if (loaded)
268 return;
270 loaded = TRUE;
272 options.file_case_sens =
273 mc_config_get_bool (mc_main_config, "FindFile", "file_case_sens", TRUE);
274 options.file_pattern =
275 mc_config_get_bool (mc_main_config, "FindFile", "file_shell_pattern", TRUE);
276 options.find_recurs = mc_config_get_bool (mc_main_config, "FindFile", "file_find_recurs", TRUE);
277 options.skip_hidden =
278 mc_config_get_bool (mc_main_config, "FindFile", "file_skip_hidden", FALSE);
279 options.file_all_charsets =
280 mc_config_get_bool (mc_main_config, "FindFile", "file_all_charsets", FALSE);
281 options.content_use = mc_config_get_bool (mc_main_config, "FindFile", "content_use", TRUE);
282 options.content_case_sens =
283 mc_config_get_bool (mc_main_config, "FindFile", "content_case_sens", TRUE);
284 options.content_regexp =
285 mc_config_get_bool (mc_main_config, "FindFile", "content_regexp", FALSE);
286 options.content_first_hit =
287 mc_config_get_bool (mc_main_config, "FindFile", "content_first_hit", FALSE);
288 options.content_whole_words =
289 mc_config_get_bool (mc_main_config, "FindFile", "content_whole_words", FALSE);
290 options.content_all_charsets =
291 mc_config_get_bool (mc_main_config, "FindFile", "content_all_charsets", FALSE);
292 options.ignore_dirs_enable =
293 mc_config_get_bool (mc_main_config, "FindFile", "ignore_dirs_enable", TRUE);
295 /* Back compatibility: try load old parameter at first */
296 ignore_dirs = mc_config_get_string (mc_main_config, "Misc", "find_ignore_dirs", "");
297 mc_config_del_key (mc_main_config, "Misc", "find_ignore_dirs");
299 /* Then load new parameters */
300 options.ignore_dirs = mc_config_get_string (mc_main_config, "FindFile", "ignore_dirs", "");
301 if (options.ignore_dirs[0] != '\0')
302 g_free (ignore_dirs);
303 else
305 g_free (options.ignore_dirs);
306 options.ignore_dirs = ignore_dirs;
309 if (options.ignore_dirs[0] == '\0')
311 g_free (options.ignore_dirs);
312 options.ignore_dirs = NULL;
316 /* --------------------------------------------------------------------------------------------- */
318 static void
319 find_save_options (void)
321 mc_config_set_bool (mc_main_config, "FindFile", "file_case_sens", options.file_case_sens);
322 mc_config_set_bool (mc_main_config, "FindFile", "file_shell_pattern", options.file_pattern);
323 mc_config_set_bool (mc_main_config, "FindFile", "file_find_recurs", options.find_recurs);
324 mc_config_set_bool (mc_main_config, "FindFile", "file_skip_hidden", options.skip_hidden);
325 mc_config_set_bool (mc_main_config, "FindFile", "file_all_charsets", options.file_all_charsets);
326 mc_config_set_bool (mc_main_config, "FindFile", "content_use", options.content_use);
327 mc_config_set_bool (mc_main_config, "FindFile", "content_case_sens", options.content_case_sens);
328 mc_config_set_bool (mc_main_config, "FindFile", "content_regexp", options.content_regexp);
329 mc_config_set_bool (mc_main_config, "FindFile", "content_first_hit", options.content_first_hit);
330 mc_config_set_bool (mc_main_config, "FindFile", "content_whole_words",
331 options.content_whole_words);
332 mc_config_set_bool (mc_main_config, "FindFile", "content_all_charsets",
333 options.content_all_charsets);
334 mc_config_set_bool (mc_main_config, "FindFile", "ignore_dirs_enable",
335 options.ignore_dirs_enable);
336 mc_config_set_string (mc_main_config, "FindFile", "ignore_dirs", options.ignore_dirs);
339 /* --------------------------------------------------------------------------------------------- */
341 static inline char *
342 add_to_list (const char *text, void *data)
344 return listbox_add_item (find_list, LISTBOX_APPEND_AT_END, 0, text, data);
347 /* --------------------------------------------------------------------------------------------- */
349 static inline void
350 stop_idle (void *data)
352 set_idle_proc (data, 0);
355 /* --------------------------------------------------------------------------------------------- */
357 static inline void
358 status_update (const char *text)
360 label_set_text (status_label, text);
363 /* --------------------------------------------------------------------------------------------- */
365 static void
366 found_num_update (void)
368 char buffer[BUF_TINY];
369 g_snprintf (buffer, sizeof (buffer), _("Found: %ld"), matches);
370 label_set_text (found_num_label, buffer);
373 /* --------------------------------------------------------------------------------------------- */
375 static void
376 get_list_info (char **file, char **dir)
378 listbox_get_current (find_list, file, (void **) dir);
381 /* --------------------------------------------------------------------------------------------- */
382 /** check regular expression */
384 static gboolean
385 find_check_regexp (const char *r)
387 mc_search_t *search;
388 gboolean regexp_ok = FALSE;
390 search = mc_search_new (r, -1);
392 if (search != NULL)
394 search->search_type = MC_SEARCH_T_REGEX;
395 regexp_ok = mc_search_prepare (search);
396 mc_search_free (search);
399 return regexp_ok;
402 /* --------------------------------------------------------------------------------------------- */
404 * Callback for the parameter dialog.
405 * Validate regex, prevent closing the dialog if it's invalid.
408 static cb_ret_t
409 find_parm_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
411 switch (msg)
413 case DLG_ACTION:
414 if (sender == (Widget *) content_use_cbox)
416 gboolean disable = !(content_use_cbox->state & C_BOOL);
418 widget_disable (content_label->widget, disable);
419 send_message ((Widget *) content_label, WIDGET_DRAW, 0);
420 widget_disable (in_with->widget, disable);
421 send_message ((Widget *) in_with, WIDGET_DRAW, 0);
422 widget_disable (content_first_hit_cbox->widget, disable);
423 send_message ((Widget *) content_first_hit_cbox, WIDGET_DRAW, 0);
424 widget_disable (content_regexp_cbox->widget, disable);
425 send_message ((Widget *) content_regexp_cbox, WIDGET_DRAW, 0);
426 widget_disable (content_case_sens_cbox->widget, disable);
427 send_message ((Widget *) content_case_sens_cbox, WIDGET_DRAW, 0);
428 #ifdef HAVE_CHARSET
429 widget_disable (content_all_charsets_cbox->widget, disable);
430 send_message ((Widget *) content_all_charsets_cbox, WIDGET_DRAW, 0);
431 #endif
432 widget_disable (content_whole_words_cbox->widget, disable);
433 send_message ((Widget *) content_whole_words_cbox, WIDGET_DRAW, 0);
435 return MSG_HANDLED;
438 if (sender == (Widget *) ignore_dirs_cbox)
440 gboolean disable = !(ignore_dirs_cbox->state & C_BOOL);
442 widget_disable (in_ignore->widget, disable);
443 send_message ((Widget *) in_ignore, WIDGET_DRAW, 0);
445 return MSG_HANDLED;
448 return MSG_NOT_HANDLED;
451 case DLG_VALIDATE:
452 if (h->ret_value != B_ENTER)
453 return MSG_HANDLED;
455 /* check filename regexp */
456 if (!(file_pattern_cbox->state & C_BOOL)
457 && (in_name->buffer[0] != '\0') && !find_check_regexp (in_name->buffer))
459 h->state = DLG_ACTIVE; /* Don't stop the dialog */
460 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
461 dlg_select_widget (in_name);
462 return MSG_HANDLED;
465 /* check content regexp */
466 if ((content_use_cbox->state & C_BOOL) && (content_regexp_cbox->state & C_BOOL)
467 && (in_with->buffer[0] != '\0') && !find_check_regexp (in_with->buffer))
469 h->state = DLG_ACTIVE; /* Don't stop the dialog */
470 message (D_ERROR, MSG_ERROR, _("Malformed regular expression"));
471 dlg_select_widget (in_with);
472 return MSG_HANDLED;
475 return MSG_HANDLED;
477 default:
478 return default_dlg_callback (h, sender, msg, parm, data);
482 /* --------------------------------------------------------------------------------------------- */
484 * find_parameters: gets information from the user
486 * If the return value is TRUE, then the following holds:
488 * START_DIR, IGNORE_FIR and PATTERN are pointers to char * and upon return they
489 * contain the information provided by the user.
491 * CONTENT holds a strdup of the contents specified by the user if he
492 * asked for them or 0 if not (note, this is different from the
493 * behavior for the other two parameters.
497 static gboolean
498 find_parameters (char **start_dir, char **ignore_dirs, char **pattern, char **content)
500 gboolean return_value;
502 /* file name */
503 const char *file_case_label = N_("Cas&e sensitive");
504 const char *file_pattern_label = N_("&Using shell patterns");
505 const char *file_recurs_label = N_("&Find recursively");
506 const char *file_skip_hidden_label = N_("S&kip hidden");
507 #ifdef HAVE_CHARSET
508 const char *file_all_charsets_label = N_("&All charsets");
509 #endif
511 /* file content */
512 const char *content_use_label = N_("Sea&rch for content");
513 const char *content_case_label = N_("Case sens&itive");
514 const char *content_regexp_label = N_("Re&gular expression");
515 const char *content_first_hit_label = N_("Fir&st hit");
516 const char *content_whole_words_label = N_("&Whole words");
517 #ifdef HAVE_CHARSET
518 const char *content_all_charsets_label = N_("A&ll charsets");
519 #endif
521 const char *buts[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
523 int b0, b1, b2;
525 int cbox_position;
526 gboolean disable;
528 #ifdef ENABLE_NLS
530 int i = sizeof (buts) / sizeof (buts[0]);
531 while (i-- != 0)
532 buts[i] = _(buts[i]);
534 file_case_label = _(file_case_label);
535 file_pattern_label = _(file_pattern_label);
536 file_recurs_label = _(file_recurs_label);
537 file_skip_hidden_label = _(file_skip_hidden_label);
538 #ifdef HAVE_CHARSET
539 file_all_charsets_label = _(file_all_charsets_label);
540 content_all_charsets_label = _(content_all_charsets_label);
541 #endif
542 content_use_label = _(content_use_label);
543 content_case_label = _(content_case_label);
544 content_regexp_label = _(content_regexp_label);
545 content_first_hit_label = _(content_first_hit_label);
546 content_whole_words_label = _(content_whole_words_label);
548 #endif /* ENABLE_NLS */
550 b0 = str_term_width1 (buts[0]) + 6; /* default button */
551 b1 = str_term_width1 (buts[1]) + 4;
552 b2 = str_term_width1 (buts[2]) + 4;
554 find_load_options ();
556 if (in_start_dir == NULL)
557 in_start_dir = g_strdup (".");
559 disable = !options.content_use;
561 find_dlg =
562 create_dlg (TRUE, 0, 0, FIND_Y, FIND_X, dialog_colors,
563 find_parm_callback, "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
565 add_widget (find_dlg,
566 button_new (FIND_Y - 3, FIND_X * 3 / 4 - b1 / 2, B_CANCEL, NORMAL_BUTTON, buts[1],
567 0));
568 add_widget (find_dlg,
569 button_new (FIND_Y - 3, FIND_X / 4 - b0 / 2, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
571 cbox_position = FIND_Y - 5;
573 content_first_hit_cbox =
574 check_new (cbox_position--, FIND_X / 2 + 1, options.content_first_hit,
575 content_first_hit_label);
576 widget_disable (content_first_hit_cbox->widget, disable);
577 add_widget (find_dlg, content_first_hit_cbox);
579 content_whole_words_cbox =
580 check_new (cbox_position--, FIND_X / 2 + 1, options.content_whole_words,
581 content_whole_words_label);
582 widget_disable (content_whole_words_cbox->widget, disable);
583 add_widget (find_dlg, content_whole_words_cbox);
585 #ifdef HAVE_CHARSET
586 content_all_charsets_cbox = check_new (cbox_position--, FIND_X / 2 + 1,
587 options.content_all_charsets,
588 content_all_charsets_label);
589 widget_disable (content_all_charsets_cbox->widget, disable);
590 add_widget (find_dlg, content_all_charsets_cbox);
591 #endif
593 content_case_sens_cbox =
594 check_new (cbox_position--, FIND_X / 2 + 1, options.content_case_sens, content_case_label);
595 widget_disable (content_case_sens_cbox->widget, disable);
596 add_widget (find_dlg, content_case_sens_cbox);
598 content_regexp_cbox =
599 check_new (cbox_position--, FIND_X / 2 + 1, options.content_regexp, content_regexp_label);
600 widget_disable (content_regexp_cbox->widget, disable);
601 add_widget (find_dlg, content_regexp_cbox);
603 cbox_position = FIND_Y - 6;
605 skip_hidden_cbox = check_new (cbox_position--, 3, options.skip_hidden, file_skip_hidden_label);
606 add_widget (find_dlg, skip_hidden_cbox);
608 #ifdef HAVE_CHARSET
609 file_all_charsets_cbox =
610 check_new (cbox_position--, 3, options.file_all_charsets, file_all_charsets_label);
611 add_widget (find_dlg, file_all_charsets_cbox);
612 #endif
614 file_case_sens_cbox = check_new (cbox_position--, 3, options.file_case_sens, file_case_label);
615 add_widget (find_dlg, file_case_sens_cbox);
617 file_pattern_cbox = check_new (cbox_position--, 3, options.file_pattern, file_pattern_label);
618 add_widget (find_dlg, file_pattern_cbox);
620 recursively_cbox = check_new (cbox_position, 3, options.find_recurs, file_recurs_label);
621 add_widget (find_dlg, recursively_cbox);
623 /* This checkbox is located in the second column */
624 content_use_cbox =
625 check_new (cbox_position, FIND_X / 2 + 1, options.content_use, content_use_label);
626 add_widget (find_dlg, content_use_cbox);
628 in_with =
629 input_new (8, FIND_X / 2 + 1, input_get_default_colors (), FIND_X / 2 - 4, INPUT_LAST_TEXT,
630 MC_HISTORY_SHARED_SEARCH, INPUT_COMPLETE_DEFAULT);
631 widget_disable (in_with->widget, disable);
632 add_widget (find_dlg, in_with);
634 content_label = label_new (7, FIND_X / 2 + 1, _("Content:"));
635 widget_disable (content_label->widget, disable);
636 add_widget (find_dlg, content_label);
638 in_name = input_new (8, 3, input_get_default_colors (),
639 FIND_X / 2 - 4, INPUT_LAST_TEXT, "name", INPUT_COMPLETE_DEFAULT);
640 add_widget (find_dlg, in_name);
641 add_widget (find_dlg, label_new (7, 3, _("File name:")));
643 in_ignore = input_new (5, 3, input_get_default_colors (), FIND_X - 6,
644 options.ignore_dirs != NULL ? options.ignore_dirs : "",
645 "ignoredirs", INPUT_COMPLETE_DEFAULT);
646 widget_disable (in_ignore->widget, !options.ignore_dirs_enable);
647 add_widget (find_dlg, in_ignore);
649 ignore_dirs_cbox =
650 check_new (4, 3, options.ignore_dirs_enable, _("Ena&ble ignore directories:"));
651 add_widget (find_dlg, ignore_dirs_cbox);
653 add_widget (find_dlg, button_new (3, FIND_X - b2 - 2, B_TREE, NORMAL_BUTTON, buts[2], 0));
655 in_start = input_new (3, 3, input_get_default_colors (),
656 FIND_X - b2 - 6, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
657 add_widget (find_dlg, in_start);
658 add_widget (find_dlg, label_new (2, 3, _("Start at:")));
660 find_par_start:
661 dlg_select_widget (in_name);
663 switch (run_dlg (find_dlg))
665 case B_CANCEL:
666 return_value = FALSE;
667 break;
669 case B_TREE:
671 const char *temp_dir = in_start->buffer;
673 if ((temp_dir[0] == '\0') || ((temp_dir[0] == '.') && (temp_dir[1] == '\0')))
674 temp_dir = current_panel->cwd;
676 if (in_start_dir != INPUT_LAST_TEXT)
677 g_free (in_start_dir);
678 in_start_dir = tree_box (temp_dir);
679 if (in_start_dir == NULL)
680 in_start_dir = g_strdup (temp_dir);
682 input_assign_text (in_start, in_start_dir);
684 /* Warning: Dreadful goto */
685 goto find_par_start;
688 default:
689 #ifdef HAVE_CHARSET
690 options.file_all_charsets = file_all_charsets_cbox->state & C_BOOL;
691 options.content_all_charsets = content_all_charsets_cbox->state & C_BOOL;
692 #endif
693 options.content_use = content_use_cbox->state & C_BOOL;
694 options.content_case_sens = content_case_sens_cbox->state & C_BOOL;
695 options.content_regexp = content_regexp_cbox->state & C_BOOL;
696 options.content_first_hit = content_first_hit_cbox->state & C_BOOL;
697 options.content_whole_words = content_whole_words_cbox->state & C_BOOL;
698 options.find_recurs = recursively_cbox->state & C_BOOL;
699 options.file_pattern = file_pattern_cbox->state & C_BOOL;
700 options.file_case_sens = file_case_sens_cbox->state & C_BOOL;
701 options.skip_hidden = skip_hidden_cbox->state & C_BOOL;
702 options.ignore_dirs_enable = ignore_dirs_cbox->state & C_BOOL;
703 g_free (options.ignore_dirs);
704 options.ignore_dirs = g_strdup (in_ignore->buffer);
706 *content = (options.content_use && in_with->buffer[0] != '\0')
707 ? g_strdup (in_with->buffer) : NULL;
708 *start_dir = in_start->buffer[0] != '\0' ? in_start->buffer : (char *) ".";
709 *pattern = g_strdup (in_name->buffer);
710 if (in_start_dir != INPUT_LAST_TEXT)
711 g_free (in_start_dir);
712 in_start_dir = g_strdup (*start_dir);
713 if ((*start_dir)[0] == '.' && (*start_dir)[1] == '\0')
714 *start_dir = g_strdup (current_panel->cwd);
715 else if (g_path_is_absolute (*start_dir))
716 *start_dir = g_strdup (*start_dir);
717 else
718 *start_dir = g_build_filename (current_panel->cwd, *start_dir, (char *) NULL);
720 canonicalize_pathname (*start_dir);
722 if (!options.ignore_dirs_enable || in_ignore->buffer[0] == '\0'
723 || (in_ignore->buffer[0] == '.' && in_ignore->buffer[1] == '\0'))
724 *ignore_dirs = NULL;
725 else
726 *ignore_dirs = g_strdup (in_ignore->buffer);
728 find_save_options ();
730 return_value = TRUE;
733 destroy_dlg (find_dlg);
735 return return_value;
738 /* --------------------------------------------------------------------------------------------- */
740 #if GLIB_CHECK_VERSION (2, 14, 0)
741 static inline void
742 push_directory (const char *dir)
744 g_queue_push_head (&dir_queue, (void *) dir);
747 /* --------------------------------------------------------------------------------------------- */
749 static inline char *
750 pop_directory (void)
752 return (char *) g_queue_pop_tail (&dir_queue);
755 /* --------------------------------------------------------------------------------------------- */
756 /** Remove all the items from the stack */
758 static void
759 clear_stack (void)
761 g_queue_foreach (&dir_queue, (GFunc) g_free, NULL);
762 g_queue_clear (&dir_queue);
765 /* --------------------------------------------------------------------------------------------- */
767 #else /* GLIB_CHECK_VERSION */
768 static void
769 push_directory (const char *dir)
771 dir_stack *new;
773 new = g_new (dir_stack, 1);
774 new->name = (char *) dir;
775 new->prev = dir_stack_base;
776 dir_stack_base = new;
779 /* --------------------------------------------------------------------------------------------- */
781 static char *
782 pop_directory (void)
784 char *name = NULL;
786 if (dir_stack_base != NULL)
788 dir_stack *next;
789 name = dir_stack_base->name;
790 next = dir_stack_base->prev;
791 g_free (dir_stack_base);
792 dir_stack_base = next;
795 return name;
798 /* --------------------------------------------------------------------------------------------- */
799 /** Remove all the items from the stack */
801 static void
802 clear_stack (void)
804 char *dir = NULL;
805 while ((dir = pop_directory ()) != NULL)
806 g_free (dir);
808 #endif /* GLIB_CHECK_VERSION */
810 /* --------------------------------------------------------------------------------------------- */
812 static void
813 insert_file (const char *dir, const char *file)
815 char *tmp_name = NULL;
816 static char *dirname = NULL;
818 while (dir[0] == PATH_SEP && dir[1] == PATH_SEP)
819 dir++;
821 if (old_dir)
823 if (strcmp (old_dir, dir))
825 g_free (old_dir);
826 old_dir = g_strdup (dir);
827 dirname = add_to_list (dir, NULL);
830 else
832 old_dir = g_strdup (dir);
833 dirname = add_to_list (dir, NULL);
836 tmp_name = g_strdup_printf (" %s", file);
837 add_to_list (tmp_name, dirname);
838 g_free (tmp_name);
841 /* --------------------------------------------------------------------------------------------- */
843 static void
844 find_add_match (const char *dir, const char *file)
846 insert_file (dir, file);
848 /* Don't scroll */
849 if (matches == 0)
850 listbox_select_first (find_list);
851 send_message (&find_list->widget, WIDGET_DRAW, 0);
853 matches++;
854 found_num_update ();
857 /* --------------------------------------------------------------------------------------------- */
859 * get_line_at:
861 * Returns malloced null-terminated line from file file_fd.
862 * Input is buffered in buf_size long buffer.
863 * Current pos in buf is stored in pos.
864 * n_read - number of read chars.
865 * has_newline - is there newline ?
868 static char *
869 get_line_at (int file_fd, char *buf, int buf_size, int *pos, int *n_read, gboolean * has_newline)
871 char *buffer = NULL;
872 int buffer_size = 0;
873 char ch = 0;
874 int i = 0;
876 for (;;)
878 if (*pos >= *n_read)
880 *pos = 0;
881 *n_read = mc_read (file_fd, buf, buf_size);
882 if (*n_read <= 0)
883 break;
886 ch = buf[(*pos)++];
887 if (ch == '\0')
889 /* skip possible leading zero(s) */
890 if (i == 0)
891 continue;
892 break;
895 if (i >= buffer_size - 1)
896 buffer = g_realloc (buffer, buffer_size += 80);
898 /* Strip newline */
899 if (ch == '\n')
900 break;
902 buffer[i++] = ch;
905 *has_newline = (ch != '\0');
907 if (buffer != NULL)
908 buffer[i] = '\0';
910 return buffer;
913 /* --------------------------------------------------------------------------------------------- */
915 static FindProgressStatus
916 check_find_events (Dlg_head * h)
918 Gpm_Event event;
919 int c;
921 event.x = -1;
922 c = tty_get_event (&event, h->mouse_status == MOU_REPEAT, FALSE);
923 if (c != EV_NONE)
925 dlg_process_event (h, c, &event);
926 if (h->ret_value == B_ENTER
927 || h->ret_value == B_CANCEL || h->ret_value == B_AGAIN || h->ret_value == B_PANELIZE)
929 /* dialog terminated */
930 return FIND_ABORT;
932 if (!(h->flags & DLG_WANT_IDLE))
934 /* searching suspended */
935 return FIND_SUSPEND;
939 return FIND_CONT;
942 /* --------------------------------------------------------------------------------------------- */
944 * search_content:
946 * Search the content_pattern string in the DIRECTORY/FILE.
947 * It will add the found entries to the find listbox.
949 * returns FALSE if do_search should look for another file
950 * TRUE if do_search should exit and proceed to the event handler
953 static gboolean
954 search_content (Dlg_head * h, const char *directory, const char *filename)
956 struct stat s;
957 char buffer[BUF_4K];
958 char *fname = NULL;
959 int file_fd;
960 gboolean ret_val = FALSE;
962 fname = concat_dir_and_file (directory, filename);
964 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode))
966 g_free (fname);
967 return FALSE;
970 file_fd = mc_open (fname, O_RDONLY);
971 g_free (fname);
973 if (file_fd == -1)
974 return FALSE;
976 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), str_trunc (filename, FIND2_X_USE));
978 status_update (buffer);
979 mc_refresh ();
981 tty_enable_interrupt_key ();
982 tty_got_interrupt ();
985 int line = 1;
986 int pos = 0;
987 int n_read = 0;
988 gboolean has_newline;
989 char *p = NULL;
990 gboolean found = FALSE;
991 gsize found_len;
992 char result[BUF_MEDIUM];
994 if (resuming)
996 /* We've been previously suspended, start from the previous position */
997 resuming = 0;
998 line = last_line;
999 pos = last_pos;
1001 while (!ret_val
1002 && (p = get_line_at (file_fd, buffer, sizeof (buffer),
1003 &pos, &n_read, &has_newline)) != NULL)
1005 if (!found /* Search in binary line once */
1006 && mc_search_run (search_content_handle,
1007 (const void *) p, 0, strlen (p), &found_len))
1009 g_snprintf (result, sizeof (result), "%d:%s", line, filename);
1010 find_add_match (directory, result);
1011 found = TRUE;
1013 g_free (p);
1015 if (found && options.content_first_hit)
1016 break;
1018 if (has_newline)
1020 found = FALSE;
1021 line++;
1024 if ((line & 0xff) == 0)
1026 FindProgressStatus res;
1027 res = check_find_events (h);
1028 switch (res)
1030 case FIND_ABORT:
1031 stop_idle (h);
1032 ret_val = TRUE;
1033 break;
1034 case FIND_SUSPEND:
1035 resuming = 1;
1036 last_line = line;
1037 last_pos = pos;
1038 ret_val = TRUE;
1039 break;
1040 default:
1041 break;
1046 tty_disable_interrupt_key ();
1047 mc_close (file_fd);
1048 return ret_val;
1051 /* --------------------------------------------------------------------------------------------- */
1054 If dir is absolute, this means we're within dir and searching file here.
1055 If dir is relative, this means we're going to add dir to the directory stack.
1057 static gboolean
1058 find_ignore_dir_search (const char *dir)
1060 if (find_ignore_dirs != NULL)
1062 const size_t dlen = strlen (dir);
1063 const unsigned char dabs = g_path_is_absolute (dir) ? 1 : 0;
1065 char **ignore_dir;
1067 for (ignore_dir = find_ignore_dirs; *ignore_dir != NULL; ignore_dir++)
1069 const size_t ilen = strlen (*ignore_dir);
1070 const unsigned char iabs = g_path_is_absolute (*ignore_dir) ? 2 : 0;
1072 /* ignore dir is too long -- skip it */
1073 if (dlen < ilen)
1074 continue;
1076 /* handle absolute and relative paths */
1077 switch (iabs | dabs)
1079 case 0: /* both paths are relative */
1080 case 3: /* both paths are abolute */
1081 /* if ignore dir is not a path of dir -- skip it */
1082 if (strncmp (dir, *ignore_dir, ilen) == 0)
1084 /* be sure that ignore dir is not a part of dir like:
1085 ignore dir is "h", dir is "home" */
1086 if (dir[ilen] == '\0' || dir[ilen] == PATH_SEP)
1087 return TRUE;
1089 break;
1090 case 1: /* dir is absolute, ignore_dir is relative */
1092 char *d;
1094 d = strstr (dir, *ignore_dir);
1095 if (d != NULL && d[-1] == PATH_SEP && (d[ilen] == '\0' || d[ilen] == PATH_SEP))
1096 return TRUE;
1098 break;
1099 case 2: /* dir is relative, ignore_dir is absolute */
1100 /* FIXME: skip this case */
1101 break;
1102 default: /* this cannot occurs */
1103 return FALSE;
1108 return FALSE;
1111 /* --------------------------------------------------------------------------------------------- */
1113 static void
1114 find_rotate_dash (const Dlg_head * h, gboolean finish)
1116 static const char rotating_dash[] = "|/-\\";
1117 static unsigned int pos = 0;
1119 if (verbose)
1121 pos = (pos + 1) % 4;
1122 tty_setcolor (h->color[DLG_COLOR_NORMAL]);
1123 dlg_move (h, FIND2_Y - 7, FIND2_X - 4);
1124 tty_print_char (finish ? ' ' : rotating_dash[pos]);
1125 mc_refresh ();
1129 /* --------------------------------------------------------------------------------------------- */
1131 static int
1132 do_search (Dlg_head * h)
1134 static struct dirent *dp = NULL;
1135 static DIR *dirp = NULL;
1136 static char *directory = NULL;
1137 struct stat tmp_stat;
1138 static int subdirs_left = 0;
1139 gsize bytes_found;
1140 unsigned short count;
1142 if (h == NULL)
1143 { /* someone forces me to close dirp */
1144 if (dirp != NULL)
1146 mc_closedir (dirp);
1147 dirp = NULL;
1149 g_free (directory);
1150 directory = NULL;
1151 dp = NULL;
1152 return 1;
1155 for (count = 0; count < 32; count++)
1157 while (dp == NULL)
1159 if (dirp != NULL)
1161 mc_closedir (dirp);
1162 dirp = NULL;
1165 while (dirp == NULL)
1167 char *tmp = NULL;
1169 tty_setcolor (REVERSE_COLOR);
1171 while (TRUE)
1173 tmp = pop_directory ();
1174 if (tmp == NULL)
1176 running = FALSE;
1177 if (ignore_count == 0)
1178 status_update (_("Finished"));
1179 else
1181 char msg[BUF_SMALL];
1182 g_snprintf (msg, sizeof (msg),
1183 ngettext ("Finished (ignored %zd directory)",
1184 "Finished (ignored %zd directories)",
1185 ignore_count), ignore_count);
1186 status_update (msg);
1188 find_rotate_dash (h, TRUE);
1189 stop_idle (h);
1190 return 0;
1193 /* handle absolute ignore dirs here */
1194 if (!find_ignore_dir_search (tmp))
1195 break;
1197 g_free (tmp);
1198 ignore_count++;
1201 g_free (directory);
1202 directory = tmp;
1204 if (verbose)
1206 char buffer[BUF_SMALL];
1208 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
1209 str_trunc (directory, FIND2_X_USE));
1210 status_update (buffer);
1212 /* mc_stat should not be called after mc_opendir
1213 because vfs_s_opendir modifies the st_nlink
1215 if (mc_stat (directory, &tmp_stat) == 0)
1216 subdirs_left = tmp_stat.st_nlink - 2;
1217 else
1218 subdirs_left = 0;
1220 dirp = mc_opendir (directory);
1221 } /* while (!dirp) */
1223 /* skip invalid filenames */
1224 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1226 } /* while (!dp) */
1228 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
1230 /* skip invalid filenames */
1231 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1234 return 1;
1237 if (!(options.skip_hidden && (dp->d_name[0] == '.')))
1239 gboolean search_ok;
1241 if ((subdirs_left != 0) && options.find_recurs && (directory != NULL))
1242 { /* Can directory be NULL ? */
1243 /* handle relative ignore dirs here */
1244 if (options.ignore_dirs_enable && find_ignore_dir_search (dp->d_name))
1245 ignore_count++;
1246 else
1248 char *tmp_name;
1250 tmp_name = g_build_filename (directory, dp->d_name, (char *) NULL);
1252 if (mc_lstat (tmp_name, &tmp_stat) == 0 && S_ISDIR (tmp_stat.st_mode))
1254 push_directory (tmp_name);
1255 subdirs_left--;
1257 else
1258 g_free (tmp_name);
1262 search_ok = mc_search_run (search_file_handle, dp->d_name,
1263 0, strlen (dp->d_name), &bytes_found);
1265 if (search_ok)
1267 if (content_pattern == NULL)
1268 find_add_match (directory, dp->d_name);
1269 else if (search_content (h, directory, dp->d_name))
1270 return 1;
1274 /* skip invalid filenames */
1275 while ((dp = mc_readdir (dirp)) != NULL && !str_is_valid_string (dp->d_name))
1277 } /* for */
1279 find_rotate_dash (h, FALSE);
1281 return 1;
1284 /* --------------------------------------------------------------------------------------------- */
1286 static void
1287 init_find_vars (void)
1289 g_free (old_dir);
1290 old_dir = NULL;
1291 matches = 0;
1292 ignore_count = 0;
1294 /* Remove all the items from the stack */
1295 clear_stack ();
1297 g_strfreev (find_ignore_dirs);
1298 find_ignore_dirs = NULL;
1301 /* --------------------------------------------------------------------------------------------- */
1303 static char *
1304 make_fullname (const char *dirname, const char *filename)
1307 if (strcmp (dirname, ".") == 0 || strcmp (dirname, "." PATH_SEP_STR) == 0)
1308 return g_strdup (filename);
1309 if (strncmp (dirname, "." PATH_SEP_STR, 2) == 0)
1310 return concat_dir_and_file (dirname + 2, filename);
1311 return concat_dir_and_file (dirname, filename);
1314 /* --------------------------------------------------------------------------------------------- */
1316 static void
1317 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
1319 char *fullname = NULL;
1320 const char *filename = NULL;
1321 int line;
1323 if (content_pattern != NULL)
1325 filename = strchr (file + 4, ':') + 1;
1326 line = atoi (file + 4);
1328 else
1330 filename = file + 4;
1331 line = 0;
1334 fullname = make_fullname (dir, filename);
1335 if (edit)
1336 do_edit_at_line (fullname, use_internal_edit, line);
1337 else
1338 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
1339 g_free (fullname);
1342 /* --------------------------------------------------------------------------------------------- */
1344 static cb_ret_t
1345 view_edit_currently_selected_file (int unparsed_view, int edit)
1347 char *dir = NULL;
1348 char *text = NULL;
1350 listbox_get_current (find_list, &text, (void **) &dir);
1352 if ((text == NULL) || (dir == NULL))
1353 return MSG_NOT_HANDLED;
1355 find_do_view_edit (unparsed_view, edit, dir, text);
1356 return MSG_HANDLED;
1359 /* --------------------------------------------------------------------------------------------- */
1361 static cb_ret_t
1362 find_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
1364 switch (msg)
1366 case DLG_KEY:
1367 if (parm == KEY_F (3) || parm == KEY_F (13))
1369 int unparsed_view = (parm == KEY_F (13));
1370 return view_edit_currently_selected_file (unparsed_view, 0);
1372 if (parm == KEY_F (4))
1374 return view_edit_currently_selected_file (0, 1);
1376 return MSG_NOT_HANDLED;
1378 case DLG_IDLE:
1379 do_search (h);
1380 return MSG_HANDLED;
1382 default:
1383 return default_dlg_callback (h, sender, msg, parm, data);
1387 /* --------------------------------------------------------------------------------------------- */
1388 /** Handles the Stop/Start button in the find window */
1390 static int
1391 start_stop (WButton * button, int action)
1393 (void) button;
1394 (void) action;
1396 running = is_start;
1397 set_idle_proc (find_dlg, running);
1398 is_start = !is_start;
1400 status_update (is_start ? _("Stopped") : _("Searching"));
1401 button_set_text (stop_button, fbuts[is_start ? 1 : 0].text);
1403 return 0;
1406 /* --------------------------------------------------------------------------------------------- */
1407 /** Handle view command, when invoked as a button */
1409 static int
1410 find_do_view_file (WButton * button, int action)
1412 (void) button;
1413 (void) action;
1415 view_edit_currently_selected_file (0, 0);
1416 return 0;
1419 /* --------------------------------------------------------------------------------------------- */
1420 /** Handle edit command, when invoked as a button */
1422 static int
1423 find_do_edit_file (WButton * button, int action)
1425 (void) button;
1426 (void) action;
1428 view_edit_currently_selected_file (0, 1);
1429 return 0;
1432 /* --------------------------------------------------------------------------------------------- */
1434 static void
1435 setup_gui (void)
1437 #ifdef ENABLE_NLS
1438 static gboolean i18n_flag = FALSE;
1440 if (!i18n_flag)
1442 int i = sizeof (fbuts) / sizeof (fbuts[0]);
1443 while (i-- != 0)
1445 fbuts[i].text = _(fbuts[i].text);
1446 fbuts[i].len = str_term_width1 (fbuts[i].text) + 3;
1449 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
1450 i18n_flag = TRUE;
1452 #endif /* ENABLE_NLS */
1455 * Dynamically place buttons centered within current window size
1458 int l0 = max (fbuts[0].len, fbuts[1].len);
1459 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
1460 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
1461 int r1, r2;
1463 /* Check, if both button rows fit within FIND2_X */
1464 FIND2_X = max (l1 + 9, COLS - 16);
1465 FIND2_X = max (l2 + 8, FIND2_X);
1467 /* compute amount of space between buttons for each row */
1468 r1 = (FIND2_X - 4 - l1) % 5;
1469 l1 = (FIND2_X - 4 - l1) / 5;
1470 r2 = (FIND2_X - 4 - l2) % 4;
1471 l2 = (FIND2_X - 4 - l2) / 4;
1473 /* ...and finally, place buttons */
1474 fbuts[2].x = 2 + r1 / 2 + l1;
1475 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
1476 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
1477 fbuts[4].x = fbuts[0].x + l0 + l1;
1478 fbuts[5].x = 2 + r2 / 2 + l2;
1479 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
1480 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
1483 find_dlg =
1484 create_dlg (TRUE, 0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
1485 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
1487 add_widget (find_dlg,
1488 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
1489 fbuts[7].text, find_do_edit_file));
1490 add_widget (find_dlg,
1491 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
1492 fbuts[6].text, find_do_view_file));
1493 add_widget (find_dlg,
1494 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON, fbuts[5].text,
1495 NULL));
1497 add_widget (find_dlg,
1498 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON, fbuts[4].text, NULL));
1499 stop_button =
1500 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON, fbuts[0].text, start_stop);
1501 add_widget (find_dlg, stop_button);
1502 add_widget (find_dlg,
1503 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON, fbuts[3].text, NULL));
1504 add_widget (find_dlg,
1505 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON, fbuts[2].text, NULL));
1507 status_label = label_new (FIND2_Y - 7, 4, _("Searching"));
1508 add_widget (find_dlg, status_label);
1510 found_num_label = label_new (FIND2_Y - 6, 4, "");
1511 add_widget (find_dlg, found_num_label);
1513 find_list = listbox_new (2, 2, FIND2_Y - 10, FIND2_X - 4, FALSE, NULL);
1514 add_widget (find_dlg, find_list);
1517 /* --------------------------------------------------------------------------------------------- */
1519 static int
1520 run_process (void)
1522 int ret;
1524 search_content_handle = mc_search_new (content_pattern, -1);
1525 if (search_content_handle)
1527 search_content_handle->search_type =
1528 options.content_regexp ? MC_SEARCH_T_REGEX : MC_SEARCH_T_NORMAL;
1529 search_content_handle->is_case_sensitive = options.content_case_sens;
1530 search_content_handle->whole_words = options.content_whole_words;
1531 search_content_handle->is_all_charsets = options.content_all_charsets;
1533 search_file_handle = mc_search_new (find_pattern, -1);
1534 search_file_handle->search_type = options.file_pattern ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
1535 search_file_handle->is_case_sensitive = options.file_case_sens;
1536 search_file_handle->is_all_charsets = options.file_all_charsets;
1537 search_file_handle->is_entire_line = options.file_pattern;
1539 resuming = 0;
1541 set_idle_proc (find_dlg, 1);
1542 ret = run_dlg (find_dlg);
1544 mc_search_free (search_file_handle);
1545 search_file_handle = NULL;
1546 mc_search_free (search_content_handle);
1547 search_content_handle = NULL;
1549 return ret;
1552 /* --------------------------------------------------------------------------------------------- */
1554 static void
1555 kill_gui (void)
1557 set_idle_proc (find_dlg, 0);
1558 destroy_dlg (find_dlg);
1561 /* --------------------------------------------------------------------------------------------- */
1563 static int
1564 find_file (const char *start_dir, const char *ignore_dirs, const char *pattern, const char *content,
1565 char **dirname, char **filename)
1567 int return_value = 0;
1568 char *dir_tmp = NULL, *file_tmp = NULL;
1570 setup_gui ();
1572 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1573 find_pattern = (char *) pattern;
1575 content_pattern = NULL;
1576 if (options.content_use && content != NULL && str_is_valid_string (content))
1577 content_pattern = g_strdup (content);
1579 init_find_vars ();
1580 parse_ignore_dirs (ignore_dirs);
1581 push_directory (start_dir);
1583 return_value = run_process ();
1585 /* Clear variables */
1586 init_find_vars ();
1588 get_list_info (&file_tmp, &dir_tmp);
1590 if (dir_tmp)
1591 *dirname = g_strdup (dir_tmp);
1592 if (file_tmp)
1593 *filename = g_strdup (file_tmp);
1595 if (return_value == B_PANELIZE && *filename)
1597 int status, link_to_dir, stale_link;
1598 int next_free = 0;
1599 int i;
1600 struct stat st;
1601 GList *entry;
1602 dir_list *list = &current_panel->dir;
1603 char *name = NULL;
1605 for (i = 0, entry = find_list->list; entry != NULL; i++, entry = g_list_next (entry))
1607 const char *lc_filename = NULL;
1608 WLEntry *le = (WLEntry *) entry->data;
1610 if ((le->text == NULL) || (le->data == NULL))
1611 continue;
1613 if (content_pattern != NULL)
1614 lc_filename = strchr (le->text + 4, ':') + 1;
1615 else
1616 lc_filename = le->text + 4;
1618 name = make_fullname (le->data, lc_filename);
1619 status = handle_path (list, name, &st, next_free, &link_to_dir, &stale_link);
1620 if (status == 0)
1622 g_free (name);
1623 continue;
1625 if (status == -1)
1627 g_free (name);
1628 break;
1631 /* don't add files more than once to the panel */
1632 if (content_pattern != NULL && next_free > 0
1633 && strcmp (list->list[next_free - 1].fname, name) == 0)
1635 g_free (name);
1636 continue;
1639 if (!next_free) /* first turn i.e clean old list */
1640 panel_clean_dir (current_panel);
1641 list->list[next_free].fnamelen = strlen (name);
1642 list->list[next_free].fname = name;
1643 list->list[next_free].f.marked = 0;
1644 list->list[next_free].f.link_to_dir = link_to_dir;
1645 list->list[next_free].f.stale_link = stale_link;
1646 list->list[next_free].f.dir_size_computed = 0;
1647 list->list[next_free].st = st;
1648 list->list[next_free].sort_key = NULL;
1649 list->list[next_free].second_sort_key = NULL;
1650 next_free++;
1651 if (!(next_free & 15))
1652 rotate_dash ();
1655 if (next_free)
1657 current_panel->count = next_free;
1658 current_panel->is_panelized = 1;
1660 if (start_dir[0] == PATH_SEP)
1662 int ret;
1663 strcpy (current_panel->cwd, PATH_SEP_STR);
1664 ret = chdir (PATH_SEP_STR);
1669 g_free (content_pattern);
1670 kill_gui ();
1671 do_search (NULL); /* force do_search to release resources */
1672 g_free (old_dir);
1673 old_dir = NULL;
1675 return return_value;
1678 /* --------------------------------------------------------------------------------------------- */
1679 /*** public functions ****************************************************************************/
1680 /* --------------------------------------------------------------------------------------------- */
1682 void
1683 do_find (void)
1685 char *start_dir = NULL, *pattern = NULL, *content = NULL, *ignore_dirs = NULL;
1686 char *filename = NULL, *dirname = NULL;
1687 int v;
1688 gboolean dir_and_file_set;
1690 while (find_parameters (&start_dir, &ignore_dirs, &pattern, &content))
1692 if (pattern[0] == '\0')
1693 break; /* nothing search */
1695 dirname = filename = NULL;
1696 is_start = FALSE;
1697 v = find_file (start_dir, ignore_dirs, pattern, content, &dirname, &filename);
1698 g_free (ignore_dirs);
1699 g_free (pattern);
1701 if (v == B_ENTER)
1703 if (dirname != NULL)
1705 do_cd (dirname, cd_exact);
1706 if (filename != NULL)
1707 try_to_select (current_panel,
1708 filename + (content != NULL
1709 ? strchr (filename + 4, ':') - filename + 1 : 4));
1711 else if (filename != NULL)
1712 do_cd (filename, cd_exact);
1714 g_free (dirname);
1715 g_free (filename);
1716 break;
1719 g_free (content);
1720 dir_and_file_set = (dirname != NULL) && (filename != NULL);
1721 g_free (dirname);
1722 g_free (filename);
1724 if (v == B_CANCEL)
1725 break;
1727 if (v == B_PANELIZE)
1729 if (dir_and_file_set)
1731 try_to_select (current_panel, NULL);
1732 panel_re_sort (current_panel);
1733 try_to_select (current_panel, NULL);
1735 break;
1740 /* --------------------------------------------------------------------------------------------- */