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
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. */
23 * \brief Source: Find file command
37 #include "../src/tty/tty.h"
38 #include "../src/skin/skin.h"
39 #include "../src/tty/key.h"
41 #include "../src/search/search.h"
49 #include "panel.h" /* current_panel */
50 #include "main.h" /* do_cd, try_to_select */
52 #include "cmd.h" /* view_file_at_line */
54 #include "history.h" /* MC_HISTORY_SHARED_SEARCH */
55 #include "layout.h" /* mc_refresh() */
57 /* Size of the find parameters window */
59 static int FIND_Y
= 16;
61 static int FIND_Y
= 15;
63 static int FIND_X
= 68;
65 /* Size of the find window */
66 #define FIND2_Y (LINES - 4)
68 static int FIND2_X
= 64;
69 #define FIND2_X_USE (FIND2_X - 20)
71 /* A couple of extra messages we need */
86 /* List of directories to be ignored, separated by ':' */
87 char *find_ignore_dirs
= NULL
;
89 /* static variables to remember find parameters */
90 static WInput
*in_start
; /* Start path */
91 static WInput
*in_name
; /* Filename */
92 static WInput
*in_with
; /* Text inside filename */
93 static WCheck
*file_case_sens_cbox
; /* "case sensitive" checkbox */
94 static WCheck
*file_pattern_cbox
; /* File name is glob or regexp */
95 static WCheck
*recursively_cbox
;
96 static WCheck
*skip_hidden_cbox
;
97 static WCheck
*content_case_sens_cbox
; /* "case sensitive" checkbox */
98 static WCheck
*content_regexp_cbox
; /* "find regular expression" checkbox */
99 static WCheck
*content_first_hit_cbox
; /* "First hit" checkbox" */
100 static WCheck
*content_whole_words_cbox
; /* "whole words" checkbox */
102 static WCheck
*file_all_charsets_cbox
;
103 static WCheck
*content_all_charsets_cbox
;
106 static gboolean running
= FALSE
; /* nice flag */
107 static char *find_pattern
= NULL
; /* Pattern to search */
108 static char *content_pattern
= NULL
; /* pattern to search inside files; if
109 content_regexp_flag is true, it contains the
110 regex pattern, else the search string. */
111 static unsigned long matches
; /* Number of matches */
112 static gboolean is_start
= FALSE
; /* Status of the start/stop toggle button */
113 static char *old_dir
= NULL
;
115 /* Where did we stop */
117 static int last_line
;
120 static Dlg_head
*find_dlg
; /* The dialog */
121 static WButton
*stop_button
; /* pointer to the stop button */
122 static WLabel
*status_label
; /* Finished, Searching etc. */
123 static WLabel
*found_num_label
; /* Number of found items */
124 static WListbox
*find_list
; /* Listbox with the file list */
126 /* This keeps track of the directory stack */
127 #if GLIB_CHECK_VERSION (2, 14, 0)
128 static GQueue dir_queue
= G_QUEUE_INIT
;
130 typedef struct dir_stack
{
132 struct dir_stack
*prev
;
135 static dir_stack
*dir_stack_base
= 0;
136 #endif /* GLIB_CHECK_VERSION */
140 int len
; /* length including space and brackets */
143 { N_("&Suspend"), 11, 29 },
144 { N_("Con&tinue"), 12, 29 },
145 { N_("&Chdir"), 11, 3 },
146 { N_("&Again"), 9, 17 },
147 { N_("&Quit"), 8, 43 },
148 { N_("Pane&lize"), 12, 3 },
149 { N_("&View - F3"), 13, 20 },
150 { N_("&Edit - F4"), 13, 38 }
153 static const char *in_contents
= NULL
;
154 static char *in_start_dir
= INPUT_LAST_TEXT
;
156 static mc_search_t
*search_file_handle
= NULL
;
157 static gboolean skip_hidden_flag
= FALSE
;
158 static gboolean file_pattern_flag
= TRUE
;
159 static gboolean file_all_charsets_flag
= FALSE
;
160 static gboolean file_case_sens_flag
= TRUE
;
161 static gboolean find_recurs_flag
= TRUE
;
163 static mc_search_t
*search_content_handle
= NULL
;
164 static gboolean content_regexp_flag
= FALSE
;
165 static gboolean content_all_charsets_flag
= FALSE
;
166 static gboolean content_case_sens_flag
= TRUE
;
167 static gboolean content_first_hit_flag
= FALSE
;
168 static gboolean content_whole_words
= FALSE
;
171 add_to_list (const char *text
, void *data
)
173 return listbox_add_item (find_list
, LISTBOX_APPEND_AT_END
, 0, text
, data
);
177 stop_idle (void *data
)
179 set_idle_proc (data
, 0);
183 status_update (const char *text
)
185 label_set_text (status_label
, text
);
189 found_num_update (void)
191 char buffer
[BUF_TINY
];
192 g_snprintf (buffer
, sizeof (buffer
), _("Found: %ld"), matches
);
193 label_set_text (found_num_label
, buffer
);
197 get_list_info (char **file
, char **dir
)
199 listbox_get_current (find_list
, file
, dir
);
202 /* check regular expression */
204 find_check_regexp (const char *r
)
207 gboolean regexp_ok
= FALSE
;
209 search
= mc_search_new (r
, -1);
211 if (search
!= NULL
) {
212 search
->search_type
= MC_SEARCH_T_REGEX
;
213 regexp_ok
= mc_search_prepare (search
);
214 mc_search_free (search
);
221 * Callback for the parameter dialog.
222 * Validate regex, prevent closing the dialog if it's invalid.
225 find_parm_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
229 if (h
->ret_value
!= B_ENTER
)
232 /* check filename regexp */
233 if (!(file_pattern_cbox
->state
& C_BOOL
)
234 && (in_name
->buffer
[0] != '\0')
235 && !find_check_regexp (in_name
->buffer
)) {
236 message (D_ERROR
, MSG_ERROR
, _(" Malformed regular expression "));
237 dlg_select_widget (in_name
);
238 h
->running
= 1; /* Don't stop the dialog */
242 /* check content regexp */
243 if ((content_regexp_cbox
->state
& C_BOOL
)
244 && (in_with
->buffer
[0] != '\0')
245 && !find_check_regexp (in_with
->buffer
)) {
246 message (D_ERROR
, MSG_ERROR
, _(" Malformed regular expression "));
247 dlg_select_widget (in_with
);
248 h
->running
= 1; /* Don't stop the dialog */
255 return default_dlg_callback (h
, msg
, parm
);
260 * find_parameters: gets information from the user
262 * If the return value is true, then the following holds:
264 * START_DIR and PATTERN are pointers to char * and upon return they
265 * contain the information provided by the user.
267 * CONTENT holds a strdup of the contents specified by the user if he
268 * asked for them or 0 if not (note, this is different from the
269 * behavior for the other two parameters.
273 find_parameters (char **start_dir
, char **pattern
, char **content
)
276 char *temp_dir
= NULL
;
279 const char *file_case_label
= N_("Cas&e sensitive");
280 const char *file_pattern_label
= N_("&Using shell patterns");
281 const char *file_recurs_label
= N_("&Find recursively");
282 const char *file_skip_hidden_label
= N_("S&kip hidden");
283 const char *file_all_charsets_label
= N_("&All charsets");
286 const char *content_case_label
= N_("Case sens&itive");
287 const char *content_regexp_label
= N_("Re&gular expression");
288 const char *content_first_hit_label
= N_("Fir&st hit");
289 const char *content_whole_words_label
= N_("&Whole words");
290 const char *content_all_charsets_label
= N_("All cha&rsets");
292 const char *buts
[] = { N_("&OK"), N_("&Cancel"), N_("&Tree") };
298 int i
= sizeof (buts
) / sizeof (buts
[0]);
300 buts
[i
] = _(buts
[i
]);
302 file_case_label
= _(file_case_label
);
303 file_pattern_label
= _(file_pattern_label
);
304 file_recurs_label
= _(file_recurs_label
);
305 file_skip_hidden_label
= _(file_skip_hidden_label
);
306 file_all_charsets_label
= _(file_all_charsets_label
);
307 content_case_label
= _(content_case_label
);
308 content_regexp_label
= _(content_regexp_label
);
309 content_first_hit_label
= _(content_first_hit_label
);
310 content_whole_words_label
= _(content_whole_words_label
);
311 content_all_charsets_label
= _(content_all_charsets_label
);
313 #endif /* ENABLE_NLS */
315 b0
= str_term_width1 (buts
[0]) + 6; /* default button */
316 b1
= str_term_width1 (buts
[1]) + 4;
317 b2
= str_term_width1 (buts
[2]) + 4;
320 if (in_contents
== NULL
)
321 in_contents
= INPUT_LAST_TEXT
;
323 if (in_start_dir
== NULL
)
324 in_start_dir
= g_strdup (".");
327 create_dlg (0, 0, FIND_Y
, FIND_X
, dialog_colors
,
328 find_parm_callback
, "[Find File]", _("Find File"),
329 DLG_CENTER
| DLG_REVERSE
);
331 add_widget (find_dlg
,
332 button_new (FIND_Y
- 3, FIND_X
* 3/4 - b1
/2, B_CANCEL
, NORMAL_BUTTON
, buts
[1], 0));
333 add_widget (find_dlg
,
334 button_new (FIND_Y
- 3, FIND_X
/4 - b0
/2, B_ENTER
, DEFPUSH_BUTTON
, buts
[0], 0));
337 content_all_charsets_cbox
= check_new (11, FIND_X
/ 2 + 1,
338 content_all_charsets_flag
, content_all_charsets_label
);
339 add_widget (find_dlg
, content_all_charsets_cbox
);
342 content_whole_words_cbox
= check_new (10, FIND_X
/ 2 + 1, content_whole_words
, content_whole_words_label
);
343 add_widget (find_dlg
, content_whole_words_cbox
);
345 content_first_hit_cbox
= check_new (9, FIND_X
/ 2 + 1, content_first_hit_flag
, content_first_hit_label
);
346 add_widget (find_dlg
, content_first_hit_cbox
);
348 content_regexp_cbox
= check_new (8, FIND_X
/ 2 + 1, content_regexp_flag
, content_regexp_label
);
349 add_widget (find_dlg
, content_regexp_cbox
);
351 content_case_sens_cbox
= check_new (7, FIND_X
/ 2 + 1, content_case_sens_flag
, content_case_label
);
352 add_widget (find_dlg
, content_case_sens_cbox
);
355 file_all_charsets_cbox
= check_new (11, 3,
356 file_all_charsets_flag
, file_all_charsets_label
);
357 add_widget (find_dlg
, file_all_charsets_cbox
);
360 skip_hidden_cbox
= check_new (10, 3, skip_hidden_flag
, file_skip_hidden_label
);
361 add_widget (find_dlg
, skip_hidden_cbox
);
363 recursively_cbox
= check_new (9, 3, find_recurs_flag
, file_recurs_label
);
364 add_widget (find_dlg
, recursively_cbox
);
366 file_pattern_cbox
= check_new (8, 3, file_pattern_flag
, file_pattern_label
);
367 add_widget (find_dlg
, file_pattern_cbox
);
369 file_case_sens_cbox
= check_new (7, 3, file_case_sens_flag
, file_case_label
);
370 add_widget (find_dlg
, file_case_sens_cbox
);
372 in_with
= input_new (6, FIND_X
/ 2 + 1, INPUT_COLOR
, FIND_X
/ 2 - 4, in_contents
,
373 MC_HISTORY_SHARED_SEARCH
, INPUT_COMPLETE_DEFAULT
);
374 add_widget (find_dlg
, in_with
);
375 add_widget (find_dlg
, label_new (5, FIND_X
/ 2 + 1, _("Content:")));
377 in_name
= input_new (6, 3, INPUT_COLOR
, FIND_X
/ 2 - 4, INPUT_LAST_TEXT
, "name",
378 INPUT_COMPLETE_DEFAULT
);
379 add_widget (find_dlg
, in_name
);
380 add_widget (find_dlg
, label_new (5, 3, _("File name:")));
382 add_widget (find_dlg
,
383 button_new (3, FIND_X
- b2
- 2, B_TREE
, NORMAL_BUTTON
, buts
[2], 0));
385 in_start
= input_new (3, 3, INPUT_COLOR
, FIND_X
- b2
- 6, in_start_dir
, "start",
386 INPUT_COMPLETE_DEFAULT
);
387 add_widget (find_dlg
, in_start
);
388 add_widget (find_dlg
, label_new (2, 3, _("Start at:")));
390 dlg_select_widget (in_name
);
392 switch (run_dlg (find_dlg
)) {
399 file_all_charsets_flag
= file_all_charsets_cbox
->state
& C_BOOL
;
400 content_all_charsets_flag
= content_all_charsets_cbox
->state
& C_BOOL
;
402 content_case_sens_flag
= content_case_sens_cbox
->state
& C_BOOL
;
403 content_regexp_flag
= content_regexp_cbox
->state
& C_BOOL
;
404 content_first_hit_flag
= content_first_hit_cbox
->state
& C_BOOL
;
405 content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
406 file_pattern_flag
= file_pattern_cbox
->state
& C_BOOL
;
407 file_case_sens_flag
= file_case_sens_cbox
->state
& C_BOOL
;
408 find_recurs_flag
= recursively_cbox
->state
& C_BOOL
;
409 skip_hidden_flag
= skip_hidden_cbox
->state
& C_BOOL
;
410 destroy_dlg (find_dlg
);
411 if (in_start_dir
!= INPUT_LAST_TEXT
)
412 g_free (in_start_dir
);
413 temp_dir
= g_strdup (in_start
->buffer
);
414 if ((temp_dir
[0] == '.') && (temp_dir
[1] == '\0')) {
416 temp_dir
= g_strdup (current_panel
->cwd
);
418 in_start_dir
= tree_box (temp_dir
);
419 if (in_start_dir
!= NULL
)
422 in_start_dir
= temp_dir
;
423 /* Warning: Dreadful goto */
429 file_all_charsets_flag
= file_all_charsets_cbox
->state
& C_BOOL
;
430 content_all_charsets_flag
= content_all_charsets_cbox
->state
& C_BOOL
;
432 content_case_sens_flag
= content_case_sens_cbox
->state
& C_BOOL
;
433 content_regexp_flag
= content_regexp_cbox
->state
& C_BOOL
;
434 content_first_hit_flag
= content_first_hit_cbox
->state
& C_BOOL
;
435 content_whole_words
= content_whole_words_cbox
->state
& C_BOOL
;
436 find_recurs_flag
= recursively_cbox
->state
& C_BOOL
;
437 file_pattern_flag
= file_pattern_cbox
->state
& C_BOOL
;
438 file_case_sens_flag
= file_case_sens_cbox
->state
& C_BOOL
;
439 skip_hidden_flag
= skip_hidden_cbox
->state
& C_BOOL
;
441 /* keep empty Content field */
442 /* if not empty, fill from history */
445 if (in_with
->buffer
[0] != '\0') {
446 *content
= g_strdup (in_with
->buffer
);
447 in_contents
= INPUT_LAST_TEXT
;
450 *start_dir
= g_strdup ((in_start
->buffer
[0] != '\0') ? in_start
->buffer
: ".");
451 *pattern
= g_strdup (in_name
->buffer
);
452 if (in_start_dir
!= INPUT_LAST_TEXT
)
453 g_free (in_start_dir
);
454 in_start_dir
= g_strdup (*start_dir
);
458 destroy_dlg (find_dlg
);
463 #if GLIB_CHECK_VERSION (2, 14, 0)
466 push_directory (const char *dir
)
468 g_queue_push_head (&dir_queue
, (void *) dir
);
474 return (char *) g_queue_pop_tail (&dir_queue
);
477 /* Remove all the items in the stack */
481 g_queue_foreach (&dir_queue
, (GFunc
) g_free
, NULL
);
482 g_queue_clear (&dir_queue
);
485 #else /* GLIB_CHAECK_VERSION */
488 push_directory (const char *dir
)
492 new = g_new (dir_stack
, 1);
493 new->name
= str_unconst (dir
);
494 new->prev
= dir_stack_base
;
495 dir_stack_base
= new;
503 if (dir_stack_base
!= NULL
) {
505 name
= dir_stack_base
->name
;
506 next
= dir_stack_base
->prev
;
507 g_free (dir_stack_base
);
508 dir_stack_base
= next
;
514 /* Remove all the items in the stack */
519 while ((dir
= pop_directory ()) != NULL
)
523 #endif /* GLIB_CHAECK_VERSION */
526 insert_file (const char *dir
, const char *file
)
528 char *tmp_name
= NULL
;
529 static char *dirname
= NULL
;
531 while (dir
[0] == PATH_SEP
&& dir
[1] == PATH_SEP
)
535 if (strcmp (old_dir
, dir
)){
537 old_dir
= g_strdup (dir
);
538 dirname
= add_to_list (dir
, NULL
);
541 old_dir
= g_strdup (dir
);
542 dirname
= add_to_list (dir
, NULL
);
545 tmp_name
= g_strdup_printf (" %s", file
);
546 add_to_list (tmp_name
, dirname
);
551 find_add_match (const char *dir
, const char *file
)
553 insert_file (dir
, file
);
557 listbox_select_by_number (find_list
, 0);
558 send_message (&find_list
->widget
, WIDGET_DRAW
, 0);
567 * Returns malloced null-terminated line from file file_fd.
568 * Input is buffered in buf_size long buffer.
569 * Current pos in buf is stored in pos.
570 * n_read - number of read chars.
571 * has_newline - is there newline ?
574 get_line_at (int file_fd
, char *buf
, int buf_size
, int *pos
, int *n_read
,
575 gboolean
*has_newline
)
583 if (*pos
>= *n_read
) {
585 *n_read
= mc_read (file_fd
, buf
, buf_size
);
592 /* skip possible leading zero(s) */
599 if (i
>= buffer_size
- 1) {
600 buffer
= g_realloc (buffer
, buffer_size
+= 80);
609 *has_newline
= (ch
!= '\0');
617 static FindProgressStatus
618 check_find_events(Dlg_head
*h
)
624 c
= tty_get_event (&event
, h
->mouse_status
== MOU_REPEAT
, FALSE
);
626 dlg_process_event (h
, c
, &event
);
627 if (h
->ret_value
== B_ENTER
628 || h
->ret_value
== B_CANCEL
629 || h
->ret_value
== B_AGAIN
630 || h
->ret_value
== B_PANELIZE
) {
631 /* dialog terminated */
634 if (!(h
->flags
& DLG_WANT_IDLE
)) {
635 /* searching suspended */
646 * Search the content_pattern string in the DIRECTORY/FILE.
647 * It will add the found entries to the find listbox.
649 * returns FALSE if do_search should look for another file
650 * TRUE if do_search should exit and proceed to the event handler
653 search_content (Dlg_head
*h
, const char *directory
, const char *filename
)
656 char buffer
[BUF_4K
];
659 gboolean ret_val
= FALSE
;
661 fname
= concat_dir_and_file (directory
, filename
);
663 if (mc_stat (fname
, &s
) != 0 || !S_ISREG (s
.st_mode
)){
668 file_fd
= mc_open (fname
, O_RDONLY
);
674 g_snprintf (buffer
, sizeof (buffer
), _("Grepping in %s"), str_trunc (filename
, FIND2_X_USE
));
676 status_update (buffer
);
679 tty_enable_interrupt_key ();
680 tty_got_interrupt ();
686 gboolean has_newline
;
688 gboolean found
= FALSE
;
690 char result
[BUF_MEDIUM
];
693 /* We've been previously suspended, start from the previous position */
699 && (p
= get_line_at (file_fd
, buffer
, sizeof (buffer
),
700 &pos
, &n_read
, &has_newline
)) != NULL
) {
701 if (!found
/* Search in binary line once */
702 && mc_search_run (search_content_handle
,
703 (const void *) p
, 0, strlen (p
), &found_len
)) {
704 g_snprintf (result
, sizeof (result
), "%d:%s", line
, filename
);
705 find_add_match (directory
, result
);
710 if (found
&& content_first_hit_flag
)
718 if ((line
& 0xff) == 0) {
719 FindProgressStatus res
;
720 res
= check_find_events(h
);
739 tty_disable_interrupt_key ();
745 do_search (struct Dlg_head
*h
)
747 static struct dirent
*dp
= NULL
;
748 static DIR *dirp
= NULL
;
749 static char *directory
= NULL
;
750 struct stat tmp_stat
;
752 static int subdirs_left
= 0;
754 unsigned long count
; /* Number of files displayed */
756 if (!h
) { /* someone forces me to close dirp */
767 search_content_handle
= mc_search_new(content_pattern
, -1);
768 if (search_content_handle
) {
769 search_content_handle
->search_type
= (content_regexp_flag
) ? MC_SEARCH_T_REGEX
: MC_SEARCH_T_NORMAL
;
770 search_content_handle
->is_case_sentitive
= content_case_sens_flag
;
771 search_content_handle
->whole_words
= content_whole_words
;
772 search_content_handle
->is_all_charsets
= content_all_charsets_flag
;
774 search_file_handle
= mc_search_new(find_pattern
, -1);
775 search_file_handle
->search_type
= (file_pattern_flag
) ? MC_SEARCH_T_GLOB
: MC_SEARCH_T_REGEX
;
776 search_file_handle
->is_case_sentitive
= file_case_sens_flag
;
777 search_file_handle
->is_all_charsets
= file_all_charsets_flag
;
778 search_file_handle
->is_entire_line
= file_pattern_flag
;
792 tty_setcolor (REVERSE_COLOR
);
794 char *temp_dir
= NULL
;
797 tmp
= pop_directory ();
800 status_update (_("Finished"));
802 mc_search_free (search_file_handle
);
803 search_file_handle
= NULL
;
804 mc_search_free (search_content_handle
);
805 search_content_handle
= NULL
;
809 if ((find_ignore_dirs
== NULL
) || (find_ignore_dirs
[0] == '\0'))
812 temp_dir
= g_strdup_printf (":%s:", tmp
);
813 found
= strstr (find_ignore_dirs
, temp_dir
) != 0;
826 char buffer
[BUF_SMALL
];
828 g_snprintf (buffer
, sizeof (buffer
), _("Searching %s"),
829 str_trunc (directory
, FIND2_X_USE
));
830 status_update (buffer
);
832 /* mc_stat should not be called after mc_opendir
833 because vfs_s_opendir modifies the st_nlink
835 if (!mc_stat (directory
, &tmp_stat
))
836 subdirs_left
= tmp_stat
.st_nlink
- 2;
840 dirp
= mc_opendir (directory
);
841 } /* while (!dirp) */
843 /* skip invalid filenames */
844 while ((dp
= mc_readdir (dirp
)) != NULL
845 && !str_is_valid_string (dp
->d_name
))
849 if (strcmp (dp
->d_name
, ".") == 0 ||
850 strcmp (dp
->d_name
, "..") == 0){
851 dp
= mc_readdir (dirp
);
852 /* skip invalid filenames */
853 while (dp
!= NULL
&& !str_is_valid_string (dp
->d_name
))
854 dp
= mc_readdir (dirp
);
856 mc_search_free(search_file_handle
);
857 search_file_handle
= NULL
;
858 mc_search_free(search_content_handle
);
859 search_content_handle
= NULL
;
863 if (!(skip_hidden_flag
&& (dp
->d_name
[0] == '.'))) {
866 if ((subdirs_left
!= 0) && find_recurs_flag
867 && (directory
!= NULL
)) { /* Can directory be NULL ? */
868 char *tmp_name
= concat_dir_and_file (directory
, dp
->d_name
);
869 if (!mc_lstat (tmp_name
, &tmp_stat
)
870 && S_ISDIR (tmp_stat
.st_mode
)) {
871 push_directory (tmp_name
);
877 search_ok
= mc_search_run (search_file_handle
, dp
->d_name
,
878 0, strlen (dp
->d_name
), &bytes_found
);
881 if (content_pattern
== NULL
)
882 find_add_match (directory
, dp
->d_name
);
883 else if (search_content (h
, directory
, dp
->d_name
)) {
884 mc_search_free(search_file_handle
);
885 search_file_handle
= NULL
;
886 mc_search_free(search_content_handle
);
887 search_content_handle
= NULL
;
893 /* skip invalid filenames */
894 while ((dp
= mc_readdir (dirp
)) != NULL
895 && !str_is_valid_string (dp
->d_name
))
898 /* Displays the nice dot */
901 /* For nice updating */
902 const char rotating_dash
[] = "|/-\\";
906 tty_setcolor (DLG_NORMALC (h
));
907 dlg_move (h
, FIND2_Y
- 7, FIND2_X
- 4);
908 tty_print_char (rotating_dash
[pos
]);
912 goto do_search_begin
;
914 mc_search_free (search_file_handle
);
915 search_file_handle
= NULL
;
916 mc_search_free (search_content_handle
);
917 search_content_handle
= NULL
;
922 init_find_vars (void)
928 /* Remove all the items in the stack */
933 make_fullname (const char *dirname
, const char *filename
)
936 if (strcmp(dirname
, ".") == 0 || strcmp(dirname
, "."PATH_SEP_STR
) == 0)
937 return g_strdup (filename
);
938 if (strncmp(dirname
, "."PATH_SEP_STR
, 2) == 0)
939 return concat_dir_and_file (dirname
+ 2, filename
);
940 return concat_dir_and_file (dirname
, filename
);
944 find_do_view_edit (int unparsed_view
, int edit
, char *dir
, char *file
)
946 char *fullname
= NULL
;
947 const char *filename
= NULL
;
950 if (content_pattern
!= NULL
) {
951 filename
= strchr (file
+ 4, ':') + 1;
952 line
= atoi (file
+ 4);
958 fullname
= make_fullname (dir
, filename
);
960 do_edit_at_line (fullname
, line
);
962 view_file_at_line (fullname
, unparsed_view
, use_internal_view
, line
);
967 view_edit_currently_selected_file (int unparsed_view
, int edit
)
969 WLEntry
*entry
= find_list
->current
;
973 return MSG_NOT_HANDLED
;
977 if (!entry
->text
|| !dir
)
978 return MSG_NOT_HANDLED
;
980 find_do_view_edit (unparsed_view
, edit
, dir
, entry
->text
);
985 find_callback (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
989 if (parm
== KEY_F (3) || parm
== KEY_F (13)) {
990 int unparsed_view
= (parm
== KEY_F (13));
991 return view_edit_currently_selected_file (unparsed_view
, 0);
993 if (parm
== KEY_F (4)) {
994 return view_edit_currently_selected_file (0, 1);
996 return MSG_NOT_HANDLED
;
1003 return default_dlg_callback (h
, msg
, parm
);
1007 /* Handles the Stop/Start button in the find window */
1009 start_stop (int button
)
1014 set_idle_proc (find_dlg
, running
);
1015 is_start
= !is_start
;
1017 status_update (is_start
? _("Stopped") : _("Searching"));
1018 button_set_text (stop_button
, fbuts
[is_start
? 1 : 0].text
);
1023 /* Handle view command, when invoked as a button */
1025 find_do_view_file (int button
)
1029 view_edit_currently_selected_file (0, 0);
1033 /* Handle edit command, when invoked as a button */
1035 find_do_edit_file (int button
)
1039 view_edit_currently_selected_file (0, 1);
1047 static gboolean i18n_flag
= FALSE
;
1050 int i
= sizeof (fbuts
) / sizeof (fbuts
[0]);
1052 fbuts
[i
].text
= _(fbuts
[i
].text
);
1053 fbuts
[i
].len
= str_term_width1 (fbuts
[i
].text
) + 3;
1056 fbuts
[2].len
+= 2; /* DEFPUSH_BUTTON */
1059 #endif /* ENABLE_NLS */
1062 * Dynamically place buttons centered within current window size
1065 int l0
= max (fbuts
[0].len
, fbuts
[1].len
);
1066 int l1
= fbuts
[2].len
+ fbuts
[3].len
+ l0
+ fbuts
[4].len
;
1067 int l2
= fbuts
[5].len
+ fbuts
[6].len
+ fbuts
[7].len
;
1070 /* Check, if both button rows fit within FIND2_X */
1071 FIND2_X
= max (l1
+ 9, COLS
- 16);
1072 FIND2_X
= max (l2
+ 8, FIND2_X
);
1074 /* compute amount of space between buttons for each row */
1075 r1
= (FIND2_X
- 4 - l1
) % 5;
1076 l1
= (FIND2_X
- 4 - l1
) / 5;
1077 r2
= (FIND2_X
- 4 - l2
) % 4;
1078 l2
= (FIND2_X
- 4 - l2
) / 4;
1080 /* ...and finally, place buttons */
1081 fbuts
[2].x
= 2 + r1
/ 2 + l1
;
1082 fbuts
[3].x
= fbuts
[2].x
+ fbuts
[2].len
+ l1
;
1083 fbuts
[0].x
= fbuts
[3].x
+ fbuts
[3].len
+ l1
;
1084 fbuts
[4].x
= fbuts
[0].x
+ l0
+ l1
;
1085 fbuts
[5].x
= 2 + r2
/ 2 + l2
;
1086 fbuts
[6].x
= fbuts
[5].x
+ fbuts
[5].len
+ l2
;
1087 fbuts
[7].x
= fbuts
[6].x
+ fbuts
[6].len
+ l2
;
1091 create_dlg (0, 0, FIND2_Y
, FIND2_X
, dialog_colors
, find_callback
,
1092 "[Find File]", _("Find File"), DLG_CENTER
| DLG_REVERSE
);
1094 add_widget (find_dlg
,
1095 button_new (FIND2_Y
- 3, fbuts
[7].x
, B_VIEW
, NORMAL_BUTTON
,
1096 fbuts
[7].text
, find_do_edit_file
));
1097 add_widget (find_dlg
,
1098 button_new (FIND2_Y
- 3, fbuts
[6].x
, B_VIEW
, NORMAL_BUTTON
,
1099 fbuts
[6].text
, find_do_view_file
));
1100 add_widget (find_dlg
,
1101 button_new (FIND2_Y
- 3, fbuts
[5].x
, B_PANELIZE
,
1102 NORMAL_BUTTON
, fbuts
[5].text
, 0));
1104 add_widget (find_dlg
,
1105 button_new (FIND2_Y
- 4, fbuts
[4].x
, B_CANCEL
,
1106 NORMAL_BUTTON
, fbuts
[4].text
, 0));
1108 button_new (FIND2_Y
- 4, fbuts
[0].x
, B_STOP
, NORMAL_BUTTON
,
1109 fbuts
[0].text
, start_stop
);
1110 add_widget (find_dlg
, stop_button
);
1111 add_widget (find_dlg
,
1112 button_new (FIND2_Y
- 4, fbuts
[3].x
, B_AGAIN
,
1113 NORMAL_BUTTON
, fbuts
[3].text
, 0));
1114 add_widget (find_dlg
,
1115 button_new (FIND2_Y
- 4, fbuts
[2].x
, B_ENTER
,
1116 DEFPUSH_BUTTON
, fbuts
[2].text
, 0));
1118 status_label
= label_new (FIND2_Y
- 7, 4, _("Searching"));
1119 add_widget (find_dlg
, status_label
);
1121 found_num_label
= label_new (FIND2_Y
- 6, 4, "");
1122 add_widget (find_dlg
, found_num_label
);
1125 listbox_new (2, 2, FIND2_Y
- 10, FIND2_X
- 4, NULL
);
1126 add_widget (find_dlg
, find_list
);
1133 set_idle_proc (find_dlg
, 1);
1134 return run_dlg (find_dlg
);
1140 set_idle_proc (find_dlg
, 0);
1141 destroy_dlg (find_dlg
);
1145 find_file (const char *start_dir
, const char *pattern
, const char *content
,
1146 char **dirname
, char **filename
)
1148 int return_value
= 0;
1149 char *dir_tmp
= NULL
, *file_tmp
= NULL
;
1153 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
1154 find_pattern
= str_unconst (pattern
);
1155 content_pattern
= (content
!= NULL
&& str_is_valid_string (content
))
1160 push_directory (start_dir
);
1162 return_value
= run_process ();
1164 /* Remove all the items in the stack */
1167 get_list_info (&file_tmp
, &dir_tmp
);
1170 *dirname
= g_strdup (dir_tmp
);
1172 *filename
= g_strdup (file_tmp
);
1174 if (return_value
== B_PANELIZE
&& *filename
) {
1175 int status
, link_to_dir
, stale_link
;
1179 WLEntry
*entry
= find_list
->list
;
1180 dir_list
*list
= ¤t_panel
->dir
;
1183 for (i
= 0; entry
!= NULL
&& i
< find_list
->count
;
1184 entry
= entry
->next
, i
++) {
1185 const char *lc_filename
= NULL
;
1187 if (!entry
->text
|| !entry
->data
)
1190 if (content_pattern
!= NULL
)
1191 lc_filename
= strchr (entry
->text
+ 4, ':') + 1;
1193 lc_filename
= entry
->text
+ 4;
1195 name
= make_fullname (entry
->data
, lc_filename
);
1197 handle_path (list
, name
, &st
, next_free
, &link_to_dir
,
1208 /* don't add files more than once to the panel */
1209 if (content_pattern
!= NULL
&& next_free
> 0
1210 && strcmp (list
->list
[next_free
- 1].fname
, name
) == 0) {
1215 if (!next_free
) /* first turn i.e clean old list */
1216 panel_clean_dir (current_panel
);
1217 list
->list
[next_free
].fnamelen
= strlen (name
);
1218 list
->list
[next_free
].fname
= name
;
1219 list
->list
[next_free
].f
.marked
= 0;
1220 list
->list
[next_free
].f
.link_to_dir
= link_to_dir
;
1221 list
->list
[next_free
].f
.stale_link
= stale_link
;
1222 list
->list
[next_free
].f
.dir_size_computed
= 0;
1223 list
->list
[next_free
].st
= st
;
1224 list
->list
[next_free
].sort_key
= NULL
;
1225 list
->list
[next_free
].second_sort_key
= NULL
;
1227 if (!(next_free
& 15))
1232 current_panel
->count
= next_free
;
1233 current_panel
->is_panelized
= 1;
1235 if (start_dir
[0] == PATH_SEP
) {
1236 strcpy (current_panel
->cwd
, PATH_SEP_STR
);
1237 chdir (PATH_SEP_STR
);
1242 g_free (content_pattern
);
1244 do_search (NULL
); /* force do_search to release resources */
1248 return return_value
;
1254 char *start_dir
= NULL
, *pattern
= NULL
, *content
= NULL
;
1255 char *filename
= NULL
, *dirname
= NULL
;
1257 gboolean dir_and_file_set
;
1259 while (find_parameters (&start_dir
, &pattern
, &content
)){
1260 if (pattern
[0] == '\0')
1261 break; /* nothing search*/
1263 dirname
= filename
= NULL
;
1265 v
= find_file (start_dir
, pattern
, content
, &dirname
, &filename
);
1269 if (dirname
|| filename
){
1271 do_cd (dirname
, cd_exact
);
1273 try_to_select (current_panel
, filename
+ (content
?
1274 (strchr (filename
+ 4, ':') - filename
+ 1) : 4) );
1275 } else if (filename
)
1276 do_cd (filename
, cd_exact
);
1277 select_item (current_panel
);
1285 dir_and_file_set
= dirname
&& filename
;
1292 if (v
== B_PANELIZE
){
1293 if (dir_and_file_set
){
1294 try_to_select (current_panel
, NULL
);
1295 panel_re_sort (current_panel
);
1296 try_to_select (current_panel
, NULL
);