Last fuzzy trimmed...
[midnight-commander.git] / src / find.c
blob09ba450e6d6976cb0c6b1b7d24eafa8e7a35e371
1 /* Find file command for the Midnight Commander
2 Copyright (C) The Free Software Foundation
3 Written 1995 by Miguel de Icaza
5 Complete rewrote.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 #include <config.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <ctype.h>
28 #include "global.h"
29 #include "tty.h"
30 #include "win.h"
31 #include "color.h"
32 #include "setup.h"
33 #include "find.h"
35 /* Dialog manager and widgets */
36 #include "dlg.h"
37 #include "widget.h"
39 #include "dialog.h" /* For do_refresh() */
40 #define DIR_H_INCLUDE_HANDLE_DIRENT
41 #include "dir.h"
42 #include "panel.h" /* current_panel */
43 #include "main.h" /* do_cd, try_to_select */
44 #include "wtools.h"
45 #include "cmd.h" /* view_file_at_line */
46 #include "boxes.h"
47 #include "../vfs/vfs.h"
49 /* Size of the find parameters window */
50 #define FIND_Y 14
51 static int FIND_X = 50;
53 /* Size of the find window */
54 #define FIND2_Y LINES-4
56 static int FIND2_X = 64;
57 #define FIND2_X_USE FIND2_X-20
59 /* A couple of extra messages we need */
60 enum {
61 B_STOP = B_USER + 1,
62 B_AGAIN,
63 B_PANELIZE,
64 B_TREE,
65 B_VIEW
68 /* A list of directories to be ignores, separated with ':' */
69 char *find_ignore_dirs = 0;
71 static WInput *in_start; /* Start path */
72 static WInput *in_name; /* Pattern to search */
73 static WInput *in_with; /* text inside filename */
74 static int running = 0; /* nice flag */
75 static char *find_pattern; /* Pattern to search */
76 static char *content_pattern; /* pattern to search inside files */
77 static int count; /* Number of files displayed */
78 static int matches; /* Number of matches */
79 static int is_start; /* Status of the start/stop toggle button */
80 static char *old_dir;
82 static Dlg_head *find_dlg; /* The dialog */
84 static WButton *stop_button; /* pointer to the stop button */
85 static WLabel *status_label; /* Finished, Searching etc. */
86 static WListbox *find_list; /* Listbox with the file list */
88 /* This keeps track of the directory stack */
89 typedef struct dir_stack {
90 char *name;
91 struct dir_stack *prev;
92 } dir_stack ;
94 static dir_stack *dir_stack_base = 0;
96 static struct {
97 char* text;
98 int len; /* length including space and brackets */
99 int x;
100 } fbuts [] = {
101 { N_("&Suspend"), 11, 29 },
102 { N_("Con&tinue"), 12, 29 },
103 { N_("&Chdir"), 11, 3 },
104 { N_("&Again"), 9, 17 },
105 { N_("&Quit"), 8, 43 },
106 { N_("Pane&lize"), 12, 3 },
107 { N_("&View - F3"), 13, 20 },
108 { N_("&Edit - F4"), 13, 38 }
111 static char *add_to_list (char *text, void *closure);
112 static void stop_idle (void *data);
113 static void status_update (char *text);
114 static void get_list_info (char **file, char **dir);
116 /* FIXME: r should be local variables */
117 static regex_t *r; /* Pointer to compiled content_pattern */
120 * find_parameters: gets information from the user
122 * If the return value is true, then the following holds:
124 * START_DIR and PATTERN are pointers to char * and upon return they
125 * contain the information provided by the user.
127 * CONTENT holds a strdup of the contents specified by the user if he
128 * asked for them or 0 if not (note, this is different from the
129 * behavior for the other two parameters.
133 static int case_sensitive = 1;
135 static int
136 find_parameters (char **start_dir, char **pattern, char **content)
138 int return_value;
139 char *temp_dir;
140 WCheck *case_sense;
141 static char* case_label = N_("case &Sensitive");
143 static char *in_contents = NULL;
144 static char *in_start_dir = NULL;
145 static char *in_start_name = NULL;
147 static char* labs[] = {N_("Start at:"), N_("Filename:"), N_("Content: ")};
148 static char* buts[] = {N_("&Ok"), N_("&Tree"), N_("&Cancel")};
149 static int ilen = 30, istart = 14;
150 static int b0 = 3, b1 = 16, b2 = 36;
152 #ifdef ENABLE_NLS
153 static int i18n_flag = 0;
155 if (!i18n_flag)
157 register int i = sizeof(labs)/sizeof(labs[0]);
158 int l1, maxlen = 0;
160 while (i--)
162 l1 = strlen (labs [i] = _(labs [i]));
163 if (l1 > maxlen)
164 maxlen = l1;
166 i = maxlen + ilen + 7;
167 if (i > FIND_X)
168 FIND_X = i;
170 for (i = sizeof(buts)/sizeof(buts[0]), l1 = 0; i--; )
172 l1 += strlen (buts [i] = _(buts [i]));
174 l1 += 21;
175 if (l1 > FIND_X)
176 FIND_X = l1;
178 ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
179 istart = FIND_X - 3 - ilen;
181 b1 = b0 + strlen(buts[0]) + 7;
182 b2 = FIND_X - (strlen(buts[2]) + 6);
184 i18n_flag = 1;
185 case_label = _(case_label);
188 #endif /* ENABLE_NLS */
190 find_par_start:
191 if (!in_start_dir)
192 in_start_dir = g_strdup (".");
193 if (!in_start_name)
194 in_start_name = g_strdup (easy_patterns ? "*" : ".");
195 if (!in_contents)
196 in_contents = g_strdup ("");
198 find_dlg = create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
199 common_dialog_callback, "[Find File]", "findfile",
200 DLG_CENTER);
202 x_set_dialog_title (find_dlg, _("Find File"));
204 add_widget (find_dlg, button_new (11, b2, B_CANCEL, NORMAL_BUTTON,
205 buts[2], 0 ,0, "cancel"));
206 add_widget (find_dlg, button_new (11, b1, B_TREE, NORMAL_BUTTON,
207 buts[1], 0, 0, "tree"));
208 add_widget (find_dlg, button_new (11, b0, B_ENTER, DEFPUSH_BUTTON,
209 buts[0], 0, 0, "ok"));
211 case_sense = check_new (9, 3, case_sensitive, case_label, "find-case-check");
212 add_widget (find_dlg, case_sense);
214 in_with = input_new (7, istart, INPUT_COLOR, ilen, in_contents, "content");
215 add_widget (find_dlg, in_with);
217 in_name = input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name");
218 add_widget (find_dlg, in_name);
220 in_start = input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start");
221 add_widget (find_dlg, in_start);
223 add_widget (find_dlg, label_new (7, 3, labs[2], "label-cont"));
224 add_widget (find_dlg, label_new (5, 3, labs[1], "label-file"));
225 add_widget (find_dlg, label_new (3, 3, labs[0], "label-start"));
227 run_dlg (find_dlg);
229 switch (find_dlg->ret_value){
230 case B_CANCEL:
231 return_value = 0;
232 break;
234 case B_TREE:
235 temp_dir = g_strdup (in_start->buffer);
236 case_sensitive = case_sense->state & C_BOOL;
237 destroy_dlg (find_dlg);
238 g_free (in_start_dir);
239 if (strcmp (temp_dir, ".") == 0){
240 g_free (temp_dir);
241 temp_dir = g_strdup (cpanel->cwd);
243 in_start_dir = tree_box (temp_dir);
244 if (in_start_dir)
245 g_free (temp_dir);
246 else
247 in_start_dir = temp_dir;
248 /* Warning: Dreadful goto */
249 goto find_par_start;
250 break;
252 default:
253 g_free (in_contents);
254 if (in_with->buffer [0]){
255 int flags = REG_EXTENDED|REG_NOSUB;
257 if (!(case_sense->state & C_BOOL))
258 flags |= REG_ICASE;
260 if (regcomp (r, in_with->buffer, flags)) {
261 *content = in_contents = NULL;
262 r = 0;
263 message (1, MSG_ERROR, _(" Malformed regular expression "));
264 return_value = 0;
265 break;
267 *content = g_strdup (in_with->buffer);
268 in_contents = g_strdup (*content);
269 } else {
270 *content = in_contents = NULL;
271 r = 0;
274 case_sensitive = case_sense->state & C_BOOL;
275 return_value = 1;
276 *start_dir = g_strdup (in_start->buffer);
277 *pattern = g_strdup (in_name->buffer);
279 g_free (in_start_dir);
280 in_start_dir = g_strdup (*start_dir);
281 g_free (in_start_name);
282 in_start_name = g_strdup (*pattern);
285 destroy_dlg (find_dlg);
287 return return_value;
290 static void
291 push_directory (char *dir)
293 dir_stack *new;
295 new = g_new (dir_stack, 1);
296 new->name = g_strdup (dir);
297 new->prev = dir_stack_base;
298 dir_stack_base = new;
301 static char*
302 pop_directory (void)
304 char *name;
305 dir_stack *next;
307 if (dir_stack_base){
308 name = dir_stack_base->name;
309 next = dir_stack_base->prev;
310 g_free (dir_stack_base);
311 dir_stack_base = next;
312 return name;
313 } else
314 return 0;
317 static void
318 insert_file (char *dir, char *file)
320 char *tmp_name;
321 static char *dirname;
322 int i;
324 if (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
325 dir++;
326 i = strlen (dir);
327 if (i){
328 if (dir [i - 1] != PATH_SEP){
329 dir [i] = PATH_SEP;
330 dir [i + 1] = 0;
334 if (old_dir){
335 if (strcmp (old_dir, dir)){
336 g_free (old_dir);
337 old_dir = g_strdup (dir);
338 dirname = add_to_list (dir, NULL);
340 } else {
341 old_dir = g_strdup (dir);
342 dirname = add_to_list (dir, NULL);
345 tmp_name = g_strconcat (" ", file, NULL);
346 add_to_list (tmp_name, dirname);
347 g_free (tmp_name);
350 static void
351 find_add_match (Dlg_head *h, char *dir, char *file)
353 int p = ++matches & 7;
355 insert_file (dir, file);
357 /* Scroll nicely */
358 if (!p)
359 listbox_select_last (find_list, 1);
360 else
361 listbox_select_last (find_list, 0);
362 /* Updates the current listing */
363 send_message (h, &find_list->widget, WIDGET_DRAW, 0);
364 if (p == 7)
365 mc_refresh ();
369 * get_line_at:
371 * Returns malloced null-terminated line from file file_fd.
372 * Input is buffered in buf_size long buffer.
373 * Current pos in buf is stored in pos.
374 * n_read - number of read chars.
375 * has_newline - is there newline ?
377 static char *
378 get_line_at (int file_fd, char *buf, int *pos, int *n_read, int buf_size, int *has_newline)
380 char *buffer = 0;
381 int buffer_size = 0;
382 char ch = 0;
383 int i = 0;
385 do {
386 if (*pos >= *n_read){
387 *pos = 0;
388 if ((*n_read = mc_read (file_fd, buf, buf_size)) <= 0)
389 break;
392 ch = buf [(*pos)++];
393 if (ch == 0) {
394 /* skip possible leading zero(s) */
395 if (i == 0)
396 continue;
397 else
398 break;
401 if (i >= buffer_size - 1){
402 buffer = g_realloc (buffer, buffer_size += 80);
405 buffer [i++] = ch;
407 } while (ch != '\n');
409 *has_newline = ch ? 1 : 0;
411 if (buffer){
412 buffer [i] = 0;
415 return buffer;
419 * search_content:
421 * Search the global (FIXME) regexp compiled content_pattern string in the
422 * DIRECTORY/FILE. It will add the found entries to the find listbox.
424 static void
425 search_content (Dlg_head *h, char *directory, char *filename)
427 struct stat s;
428 char buffer [BUF_SMALL];
429 char *fname;
430 int file_fd;
432 fname = concat_dir_and_file (directory, filename);
434 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode)){
435 g_free (fname);
436 return;
439 file_fd = mc_open (fname, O_RDONLY);
440 g_free (fname);
442 if (file_fd == -1)
443 return;
445 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
447 status_update (buffer);
448 mc_refresh ();
450 enable_interrupt_key ();
451 got_interrupt ();
454 int line = 1;
455 int pos = 0;
456 int n_read = 0;
457 int has_newline;
458 char *p;
459 int found = 0;
461 while ((p = get_line_at (file_fd, buffer, &pos, &n_read, sizeof (buffer), &has_newline))){
462 if (found == 0){ /* Search in binary line once */
463 if (regexec (r, p, 1, 0, 0) == 0){
464 g_free (p);
465 p = g_strdup_printf ("%d:%s", line, filename);
466 find_add_match (h, directory, p);
467 found = 1;
470 if (has_newline){
471 line++;
472 found = 0;
474 g_free (p);
477 disable_interrupt_key ();
478 mc_close (file_fd);
481 static int
482 do_search (struct Dlg_head *h)
484 static struct dirent *dp = 0;
485 static DIR *dirp = 0;
486 static char directory [MC_MAXPATHLEN+2];
487 struct stat tmp_stat;
488 static int pos;
489 static int subdirs_left = 0;
490 char *tmp_name; /* For building file names */
492 if (!h) { /* someone forces me to close dirp */
493 if (dirp) {
494 mc_closedir (dirp);
495 dirp = 0;
497 dp = 0;
498 return 1;
500 do_search_begin:
501 while (!dp){
503 if (dirp){
504 mc_closedir (dirp);
505 dirp = 0;
508 while (!dirp){
509 char *tmp;
511 attrset (REVERSE_COLOR);
512 while (1) {
513 tmp = pop_directory ();
514 if (!tmp){
515 running = 0;
516 status_update (_("Finished"));
517 stop_idle (h);
518 return 0;
520 if (find_ignore_dirs){
521 int found;
522 char *temp_dir = g_strconcat (":", tmp, ":", NULL);
524 found = strstr (find_ignore_dirs, temp_dir) != 0;
525 g_free (temp_dir);
526 if (found)
527 g_free (tmp);
528 else
529 break;
530 } else
531 break;
534 strcpy (directory, tmp);
535 g_free (tmp);
537 if (verbose){
538 char buffer [BUF_SMALL];
540 g_snprintf (buffer, sizeof (buffer), _("Searching %s"), name_trunc (directory, FIND2_X_USE));
541 status_update (buffer);
543 /* mc_stat should not be called after mc_opendir
544 because vfs_s_opendir modifies the st_nlink
546 mc_stat (directory, &tmp_stat);
547 subdirs_left = tmp_stat.st_nlink - 2;
548 /* Commented out as unnecessary
549 if (subdirs_left < 0)
550 subdirs_left = MAXINT;
552 dirp = mc_opendir (directory);
554 dp = mc_readdir (dirp);
557 if (strcmp (dp->d_name, ".") == 0 ||
558 strcmp (dp->d_name, "..") == 0){
559 dp = mc_readdir (dirp);
560 return 1;
563 tmp_name = concat_dir_and_file (directory, dp->d_name);
565 if (subdirs_left){
566 mc_lstat (tmp_name, &tmp_stat);
567 if (S_ISDIR (tmp_stat.st_mode)){
568 push_directory (tmp_name);
569 subdirs_left--;
573 if (regexp_match (find_pattern, dp->d_name, match_file)){
574 if (content_pattern)
575 search_content (h, directory, dp->d_name);
576 else
577 find_add_match (h, directory, dp->d_name);
580 g_free (tmp_name);
581 dp = mc_readdir (dirp);
583 /* Displays the nice dot */
584 count++;
585 if (!(count & 31)){
586 /* For nice updating */
587 char *rotating_dash = "|/-\\";
589 if (verbose){
590 pos = (pos + 1) % 4;
591 attrset (NORMALC);
592 dlg_move (h, FIND2_Y-6, FIND2_X - 4);
593 addch (rotating_dash [pos]);
594 mc_refresh ();
596 } else
597 goto do_search_begin;
598 return 1;
601 static void
602 init_find_vars (void)
604 char *dir;
606 if (old_dir){
607 g_free (old_dir);
608 old_dir = 0;
610 count = 0;
611 matches = 0;
613 /* Remove all the items in the stack */
614 while ((dir = pop_directory ()) != NULL)
615 g_free (dir);
618 static void
619 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
621 char *fullname, *filename;
622 int line;
624 if (content_pattern){
625 filename = strchr (file + 4, ':') + 1;
626 line = atoi (file + 4);
627 } else {
628 filename = file + 4;
629 line = 0;
631 if (dir [0] == '.' && dir [1] == 0)
632 fullname = g_strdup (filename);
633 else if (dir [0] == '.' && dir [1] == PATH_SEP)
634 fullname = concat_dir_and_file (dir+2, filename);
635 else
636 fullname = concat_dir_and_file (dir, filename);
638 if (edit)
639 do_edit_at_line (fullname, line);
640 else
641 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
642 g_free (fullname);
645 static void
646 get_list_info (char **file, char **dir)
648 listbox_get_current (find_list, file, dir);
651 static char *
652 add_to_list (char *text, void *data)
654 return listbox_add_item (find_list, 0, 0, text, data);
657 static void
658 stop_idle (void *data)
660 set_idle_proc (data, 0);
663 static int
664 view_edit_currently_selected_file (int unparsed_view, int edit)
666 WLEntry *entry = find_list->current;
667 char *dir;
669 if (!entry)
670 return MSG_NOT_HANDLED;
672 dir = entry->data;
674 if (!entry->text || !dir)
675 return MSG_NOT_HANDLED;
677 find_do_view_edit (unparsed_view, edit, dir, entry->text);
678 return MSG_HANDLED;
681 static int
682 find_callback (struct Dlg_head *h, int id, int Msg)
684 switch (Msg){
685 case DLG_DRAW:
686 common_dialog_repaint (h);
687 break;
689 case DLG_KEY:
690 if (id == KEY_F(3) || id == KEY_F(13)){
691 int unparsed_view = (id == KEY_F(13));
692 return view_edit_currently_selected_file (unparsed_view, 0);
694 if (id == KEY_F(4)){
695 return view_edit_currently_selected_file (0, 1);
697 return MSG_NOT_HANDLED;
699 case DLG_IDLE:
700 do_search (h);
701 break;
703 return 0;
706 /* Handles the Stop/Start button in the find window */
707 static int
708 start_stop (int button, void *extra)
710 running = is_start;
711 set_idle_proc (find_dlg, running);
712 is_start = !is_start;
714 status_update (is_start ? _("Stopped") : _("Searching"));
715 button_set_text (stop_button, fbuts [is_start].text);
717 return 0;
720 /* Handle view command, when invoked as a button */
721 static int
722 find_do_view_file (int button, void *extra)
724 view_edit_currently_selected_file (0, 0);
725 return 0;
728 /* Handle edit command, when invoked as a button */
729 static int
730 find_do_edit_file (int button, void *extra)
732 view_edit_currently_selected_file (0, 1);
733 return 0;
736 static void
737 setup_gui (void)
739 #ifdef ENABLE_NLS
740 static int i18n_flag = 0;
741 if (!i18n_flag)
743 register int i = sizeof (fbuts) / sizeof (fbuts[0]);
744 while (i--)
745 fbuts [i].len = strlen (fbuts [i].text = _(fbuts [i].text)) + 3;
746 fbuts [2].len += 2; /* DEFPUSH_BUTTON */
747 i18n_flag = 1;
749 #endif /* ENABLE_NLS */
752 * Dynamically place buttons centered within current window size
755 int l0 = max (fbuts[0].len, fbuts[1].len);
756 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
757 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
758 int r1, r2;
760 FIND2_X = COLS - 16;
762 /* Check, if both button rows fit within FIND2_X */
763 if (l1 + 9 > FIND2_X) FIND2_X = l1 + 9;
764 if (l2 + 8 > FIND2_X) FIND2_X = l2 + 8;
766 /* compute amount of space between buttons for each row */
767 r1 = (FIND2_X - 4 - l1) % 5;
768 l1 = (FIND2_X - 4 - l1) / 5;
769 r2 = (FIND2_X - 4 - l2) % 4;
770 l2 = (FIND2_X - 4 - l2) / 4;
772 /* ...and finally, place buttons */
773 fbuts [2].x = 2 + r1/2 + l1;
774 fbuts [3].x = fbuts [2].x + fbuts [2].len + l1;
775 fbuts [0].x = fbuts [3].x + fbuts [3].len + l1;
776 fbuts [4].x = fbuts [0].x + l0 + l1;
777 fbuts [5].x = 2 + r2/2 + l2;
778 fbuts [6].x = fbuts [5].x + fbuts [5].len + l2;
779 fbuts [7].x = fbuts [6].x + fbuts [6].len + l2;
782 find_dlg = create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors,
783 find_callback, "[Find File]", "mfind", DLG_CENTER);
785 x_set_dialog_title (find_dlg, _("Find file"));
787 add_widget (find_dlg,
788 button_new (FIND2_Y-3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
789 fbuts[7].text, find_do_edit_file, find_dlg, "button-edit"));
790 add_widget (find_dlg,
791 button_new (FIND2_Y-3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
792 fbuts[6].text, find_do_view_file, find_dlg, "button-view"));
793 add_widget (find_dlg,
794 button_new (FIND2_Y-3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON,
795 fbuts[5].text, 0, 0, "button-panelize"));
797 add_widget (find_dlg,
798 button_new (FIND2_Y-4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON,
799 fbuts[4].text, 0, 0, "button-quit"));
800 stop_button = button_new (FIND2_Y-4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
801 fbuts[0].text, start_stop, find_dlg, "start-stop");
802 add_widget (find_dlg, stop_button);
803 add_widget (find_dlg,
804 button_new (FIND2_Y-4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON,
805 fbuts[3].text, 0, 0, "button-again"));
806 add_widget (find_dlg,
807 button_new (FIND2_Y-4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON,
808 fbuts[2].text, 0, 0, "button-chdir"));
810 status_label = label_new (FIND2_Y-6, 4, _("Searching"), "label-search");
811 add_widget (find_dlg, status_label);
813 find_list = listbox_new (2, 2, FIND2_X-4, FIND2_Y-9, listbox_finish, 0, "listbox");
814 add_widget (find_dlg, find_list);
817 static int
818 run_process (void)
820 set_idle_proc (find_dlg, 1);
821 run_dlg (find_dlg);
822 return find_dlg->ret_value;
825 static void
826 status_update (char *text)
828 label_set_text (status_label, text);
831 static void
832 kill_gui (void)
834 set_idle_proc (find_dlg, 0);
835 destroy_dlg (find_dlg);
838 static int
839 find_file (char *start_dir, char *pattern, char *content, char **dirname, char **filename)
841 int return_value = 0;
842 char *dir;
843 char *dir_tmp, *file_tmp;
845 setup_gui ();
847 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
848 find_pattern = pattern;
849 content_pattern = content;
851 init_find_vars ();
852 push_directory (start_dir);
854 return_value = run_process ();
856 /* Remove all the items in the stack */
857 while ((dir = pop_directory ()) != NULL)
858 g_free (dir);
860 get_list_info (&file_tmp, &dir_tmp);
862 if (dir_tmp)
863 *dirname = g_strdup (dir_tmp);
864 if (file_tmp)
865 *filename = g_strdup (file_tmp);
867 if (return_value == B_PANELIZE && *filename){
868 int status, link_to_dir, stalled_link;
869 int next_free = 0;
870 int i;
871 struct stat buf;
872 WLEntry *entry = find_list->list;
873 dir_list *list = &cpanel->dir;
874 char *dir, *name;
876 for (i = 0; entry && i < find_list->count; entry = entry->next, i++){
877 char *filename;
879 if (content_pattern)
880 filename = strchr (entry->text+4, ':')+1;
881 else
882 filename = entry->text+4;
884 if (!entry->text || !entry->data)
885 continue;
886 dir = entry->data;
887 if (dir [0] == '.' && dir [1] == 0)
888 name = g_strdup (filename);
889 else if (dir [0] == '.' && dir [1] == PATH_SEP)
890 name = concat_dir_and_file (dir + 2, filename);
891 else
892 name = concat_dir_and_file (dir, filename);
893 status = handle_path (list, name, &buf, next_free, &link_to_dir,
894 &stalled_link);
895 if (status == 0) {
896 g_free (name);
897 continue;
899 if (status == -1) {
900 g_free (name);
901 break;
904 /* don't add files more than once to the panel */
905 if (content_pattern && next_free > 0){
906 if (strcmp (list->list [next_free-1].fname, name) == 0) {
907 g_free (name);
908 continue;
912 if (!next_free) /* first turn i.e clean old list */
913 panel_clean_dir (cpanel);
914 list->list [next_free].fnamelen = strlen (name);
915 list->list [next_free].fname = name;
916 file_mark (cpanel, next_free, 0);
917 list->list [next_free].f.link_to_dir = link_to_dir;
918 list->list [next_free].f.stalled_link = stalled_link;
919 list->list [next_free].f.dir_size_computed = 0;
920 list->list [next_free].buf = buf;
921 next_free++;
922 if (!(next_free & 15))
923 rotate_dash ();
925 if (next_free){
926 cpanel->count = next_free;
927 cpanel->is_panelized = 1;
928 /* Done by panel_clean_dir a few lines above
929 cpanel->dirs_marked = 0;
930 cpanel->marked = 0;
931 cpanel->total = 0;
932 cpanel->top_file = 0;
933 cpanel->selected = 0;*/
935 if (start_dir [0] == PATH_SEP){
936 strcpy (cpanel->cwd, PATH_SEP_STR);
937 chdir (PATH_SEP_STR);
942 kill_gui ();
943 do_search (0); /* force do_search to release resources */
944 if (old_dir){
945 g_free (old_dir);
946 old_dir = 0;
948 return return_value;
951 void
952 do_find (void)
954 char *start_dir, *pattern, *content;
955 char *filename, *dirname;
956 int v, dir_and_file_set;
957 regex_t rx; /* Compiled content_pattern to search inside files */
959 for (r = &rx; find_parameters (&start_dir, &pattern, &content); r = &rx){
961 dirname = filename = NULL;
962 is_start = 0;
963 v = find_file (start_dir, pattern, content, &dirname, &filename);
964 g_free (start_dir);
965 g_free (pattern);
966 if (r)
967 regfree (r);
969 if (v == B_ENTER){
970 if (dirname || filename){
971 if (dirname){
972 do_cd (dirname, cd_exact);
973 if (filename)
974 try_to_select (cpanel, filename + (content ?
975 (strchr (filename + 4, ':') - filename + 1) : 4) );
976 } else if (filename)
977 do_cd (filename, cd_exact);
978 paint_panel (cpanel);
979 select_item (cpanel);
981 if (dirname)
982 g_free (dirname);
983 if (filename)
984 g_free (filename);
985 break;
987 if (content)
988 g_free (content);
989 dir_and_file_set = dirname && filename;
990 if (dirname) g_free (dirname);
991 if (filename) g_free (filename);
992 if (v == B_CANCEL)
993 break;
995 if (v == B_PANELIZE){
996 if (dir_and_file_set){
997 try_to_select (cpanel, NULL);
998 panel_re_sort (cpanel);
999 paint_panel (cpanel);
1001 break;