replaced gboolean by bool (from mhl/types.h)
[midnight-commander.git] / src / find.c
blobb41b06cc5b6114d02ee6d3ec47c405ee73ef2132
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 rewrote.
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 #include <config.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
30 #include <mhl/types.h>
31 #include <mhl/string.h>
33 #include "global.h"
34 #include "tty.h"
35 #include "win.h"
36 #include "color.h"
37 #include "setup.h"
38 #include "find.h"
40 /* Dialog manager and widgets */
41 #include "dialog.h"
42 #include "widget.h"
44 #include "dir.h"
45 #include "panel.h" /* current_panel */
46 #include "main.h" /* do_cd, try_to_select */
47 #include "wtools.h"
48 #include "cmd.h" /* view_file_at_line */
49 #include "boxes.h"
50 #include "key.h"
52 /* Size of the find parameters window */
53 #define FIND_Y 15
54 static int FIND_X = 50;
56 /* Size of the find window */
57 #define FIND2_Y (LINES - 4)
59 static int FIND2_X = 64;
60 #define FIND2_X_USE (FIND2_X - 20)
62 /* A couple of extra messages we need */
63 enum {
64 B_STOP = B_USER + 1,
65 B_AGAIN,
66 B_PANELIZE,
67 B_TREE,
68 B_VIEW
71 typedef enum {
72 FIND_CONT,
73 FIND_SUSPEND,
74 FIND_ABORT
75 } FindProgressStatus;
77 /* List of directories to be ignored, separated by ':' */
78 char *find_ignore_dirs = 0;
80 static WInput *in_start; /* Start path */
81 static WInput *in_name; /* Pattern to search */
82 static WInput *in_with; /* Text inside filename */
83 static WCheck *case_sense; /* "case sensitive" checkbox */
84 static WCheck *find_regex_cbox; /* [x] find regular expression */
86 static int running = 0; /* nice flag */
87 static char *find_pattern; /* Pattern to search */
88 static char *content_pattern; /* pattern to search inside files; if
89 find_regex_flag is true, it contains the
90 regex pattern, else the search string. */
91 static int count; /* Number of files displayed */
92 static int matches; /* Number of matches */
93 static int is_start; /* Status of the start/stop toggle button */
94 static char *old_dir;
96 /* Where did we stop */
97 static int resuming;
98 static int last_line;
99 static int last_pos;
101 static Dlg_head *find_dlg; /* The dialog */
103 static WButton *stop_button; /* pointer to the stop button */
104 static WLabel *status_label; /* Finished, Searching etc. */
105 static WListbox *find_list; /* Listbox with the file list */
107 /* This keeps track of the directory stack */
108 typedef struct dir_stack {
109 char *name;
110 struct dir_stack *prev;
111 } dir_stack ;
113 static dir_stack *dir_stack_base = 0;
115 static struct {
116 const char* text;
117 int len; /* length including space and brackets */
118 int x;
119 } fbuts [] = {
120 { N_("&Suspend"), 11, 29 },
121 { N_("Con&tinue"), 12, 29 },
122 { N_("&Chdir"), 11, 3 },
123 { N_("&Again"), 9, 17 },
124 { N_("&Quit"), 8, 43 },
125 { N_("Pane&lize"), 12, 3 },
126 { N_("&View - F3"), 13, 20 },
127 { N_("&Edit - F4"), 13, 38 }
130 static inline char * add_to_list (const char *text, void *data) {
131 return listbox_add_item (find_list, 0, 0, text, data);
133 static inline void stop_idle (void *data) {
134 set_idle_proc (data, 0);
136 static inline void status_update (const char *text) {
137 label_set_text (status_label, text);
139 static void get_list_info (char **file, char **dir) {
140 listbox_get_current (find_list, file, dir);
143 /* FIXME: r should be local variable */
144 static regex_t *r; /* Pointer to compiled content_pattern */
146 static int case_sensitive = 1;
147 static bool find_regex_flag = TRUE;
148 static int find_recursively = 1;
151 * Callback for the parameter dialog.
152 * Validate regex, prevent closing the dialog if it's invalid.
154 static cb_ret_t
155 find_parm_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
157 int flags;
159 switch (msg) {
160 case DLG_VALIDATE:
161 if ((h->ret_value != B_ENTER) || !in_with->buffer[0]
162 || !(find_regex_cbox->state & C_BOOL))
163 return MSG_HANDLED;
165 flags = REG_EXTENDED | REG_NOSUB;
167 if (!(case_sense->state & C_BOOL))
168 flags |= REG_ICASE;
170 if (regcomp (r, in_with->buffer, flags)) {
171 message (D_ERROR, MSG_ERROR, _(" Malformed regular expression "));
172 dlg_select_widget (in_with);
173 h->running = 1; /* Don't stop the dialog */
175 return MSG_HANDLED;
177 default:
178 return default_dlg_callback (h, msg, parm);
183 * find_parameters: gets information from the user
185 * If the return value is true, then the following holds:
187 * START_DIR and PATTERN are pointers to char * and upon return they
188 * contain the information provided by the user.
190 * CONTENT holds a strdup of the contents specified by the user if he
191 * asked for them or 0 if not (note, this is different from the
192 * behavior for the other two parameters.
195 static int
196 find_parameters (char **start_dir, char **pattern, char **content)
198 int return_value;
199 char *temp_dir;
200 static const char *case_label = N_("case &Sensitive");
201 static const char *recurs_label = N_("&Find recursively");
203 WCheck *recursively_cbox;
205 static char *in_contents = NULL;
206 static char *in_start_dir = NULL;
207 static char *in_start_name = NULL;
209 static const char *labs[] =
210 { N_("Start at:"), N_("Filename:"), N_("Content: ") };
211 static const char *buts[] = { N_("&OK"), N_("&Tree"), N_("&Cancel") };
212 static int ilen = 30, istart = 14;
213 static int b0 = 3, b1 = 16, b2 = 36;
215 #ifdef ENABLE_NLS
216 static int i18n_flag = 0;
218 if (!i18n_flag) {
219 register int i = sizeof (labs) / sizeof (labs[0]);
220 int l1, maxlen = 0;
222 while (i--) {
223 l1 = strlen (labs[i] = _(labs[i]));
224 if (l1 > maxlen)
225 maxlen = l1;
227 i = maxlen + ilen + 7;
228 if (i > FIND_X)
229 FIND_X = i;
231 for (i = sizeof (buts) / sizeof (buts[0]), l1 = 0; i--;) {
232 l1 += strlen (buts[i] = _(buts[i]));
234 l1 += 21;
235 if (l1 > FIND_X)
236 FIND_X = l1;
238 ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
239 istart = FIND_X - 3 - ilen;
241 b1 = b0 + strlen (buts[0]) + 7;
242 b2 = FIND_X - (strlen (buts[2]) + 6);
244 i18n_flag = 1;
245 case_label = _(case_label);
246 recurs_label = _(recurs_label);
248 #endif /* ENABLE_NLS */
250 find_par_start:
251 if (!in_start_dir)
252 in_start_dir = g_strdup (".");
253 if (!in_start_name)
254 in_start_name = g_strdup (easy_patterns ? "*" : ".");
255 if (!in_contents)
256 in_contents = g_strdup ("");
258 find_dlg =
259 create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
260 find_parm_callback, "[Find File]", _("Find File"),
261 DLG_CENTER | DLG_REVERSE);
263 add_widget (find_dlg,
264 button_new (12, b2, B_CANCEL, NORMAL_BUTTON, buts[2], 0));
265 add_widget (find_dlg,
266 button_new (12, b1, B_TREE, NORMAL_BUTTON, buts[1], 0));
267 add_widget (find_dlg,
268 button_new (12, b0, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
270 recursively_cbox =
271 check_new (6, istart, find_recursively, recurs_label);
273 find_regex_cbox = check_new (10, istart, find_regex_flag, _("&Regular expression"));
274 add_widget (find_dlg, find_regex_cbox);
276 case_sense = check_new (9, istart, case_sensitive, case_label);
277 add_widget (find_dlg, case_sense);
279 in_with =
280 input_new (8, istart, INPUT_COLOR, ilen, in_contents, "content", INPUT_COMPLETE_DEFAULT);
281 add_widget (find_dlg, in_with);
283 add_widget (find_dlg, recursively_cbox);
284 in_name =
285 input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name", INPUT_COMPLETE_DEFAULT);
286 add_widget (find_dlg, in_name);
288 in_start =
289 input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
290 add_widget (find_dlg, in_start);
292 add_widget (find_dlg, label_new (8, 3, labs[2]));
293 add_widget (find_dlg, label_new (5, 3, labs[1]));
294 add_widget (find_dlg, label_new (3, 3, labs[0]));
296 dlg_select_widget (in_name);
298 run_dlg (find_dlg);
300 switch (find_dlg->ret_value) {
301 case B_CANCEL:
302 return_value = 0;
303 break;
305 case B_TREE:
306 temp_dir = g_strdup (in_start->buffer);
307 case_sensitive = case_sense->state & C_BOOL;
308 find_regex_flag = find_regex_cbox->state & C_BOOL;
309 find_recursively = recursively_cbox->state & C_BOOL;
310 destroy_dlg (find_dlg);
311 g_free (in_start_dir);
312 if (strcmp (temp_dir, ".") == 0) {
313 g_free (temp_dir);
314 temp_dir = g_strdup (current_panel->cwd);
316 in_start_dir = tree_box (temp_dir);
317 if (in_start_dir)
318 g_free (temp_dir);
319 else
320 in_start_dir = temp_dir;
321 /* Warning: Dreadful goto */
322 goto find_par_start;
323 break;
325 default:
326 g_free (in_contents);
327 if (in_with->buffer[0]) {
328 *content = g_strdup (in_with->buffer);
329 in_contents = g_strdup (*content);
330 } else {
331 *content = in_contents = NULL;
332 r = 0;
335 case_sensitive = case_sense->state & C_BOOL;
336 find_regex_flag = find_regex_cbox->state & C_BOOL;
337 find_recursively = recursively_cbox->state & C_BOOL;
338 return_value = 1;
339 *start_dir = g_strdup (in_start->buffer);
340 *pattern = g_strdup (in_name->buffer);
342 g_free (in_start_dir);
343 in_start_dir = g_strdup (*start_dir);
344 g_free (in_start_name);
345 in_start_name = g_strdup (*pattern);
348 destroy_dlg (find_dlg);
350 return return_value;
353 static void
354 push_directory (const char *dir)
356 dir_stack *new;
358 new = g_new (dir_stack, 1);
359 new->name = mhl_str_dir_plus_file (dir, NULL);
360 new->prev = dir_stack_base;
361 dir_stack_base = new;
364 static char*
365 pop_directory (void)
367 char *name;
368 dir_stack *next;
370 if (dir_stack_base){
371 name = dir_stack_base->name;
372 next = dir_stack_base->prev;
373 g_free (dir_stack_base);
374 dir_stack_base = next;
375 return name;
376 } else
377 return 0;
380 static void
381 insert_file (const char *dir, const char *file)
383 char *tmp_name;
384 static char *dirname;
386 while (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
387 dir++;
389 if (old_dir){
390 if (strcmp (old_dir, dir)){
391 g_free (old_dir);
392 old_dir = g_strdup (dir);
393 dirname = add_to_list (dir, NULL);
395 } else {
396 old_dir = g_strdup (dir);
397 dirname = add_to_list (dir, NULL);
400 tmp_name = g_strconcat (" ", file, (char *) NULL);
401 add_to_list (tmp_name, dirname);
402 g_free (tmp_name);
405 static void
406 find_add_match (Dlg_head *h, const char *dir, const char *file)
408 int p = ++matches & 7;
410 (void) h;
412 insert_file (dir, file);
414 /* Scroll nicely */
415 if (!p)
416 listbox_select_last (find_list, 1);
417 else
418 listbox_select_last (find_list, 0);
419 /* Updates the current listing */
420 send_message (&find_list->widget, WIDGET_DRAW, 0);
421 if (p == 7)
422 mc_refresh ();
426 * get_line_at:
428 * Returns malloced null-terminated line from file file_fd.
429 * Input is buffered in buf_size long buffer.
430 * Current pos in buf is stored in pos.
431 * n_read - number of read chars.
432 * has_newline - is there newline ?
434 static char *
435 get_line_at (int file_fd, char *buf, int *pos, int *n_read, int buf_size,
436 int *has_newline)
438 char *buffer = 0;
439 int buffer_size = 0;
440 char ch = 0;
441 int i = 0;
443 for (;;) {
444 if (*pos >= *n_read) {
445 *pos = 0;
446 if ((*n_read = mc_read (file_fd, buf, buf_size)) <= 0)
447 break;
450 ch = buf[(*pos)++];
451 if (ch == 0) {
452 /* skip possible leading zero(s) */
453 if (i == 0)
454 continue;
455 else
456 break;
459 if (i >= buffer_size - 1) {
460 buffer = g_realloc (buffer, buffer_size += 80);
462 /* Strip newline */
463 if (ch == '\n')
464 break;
466 buffer[i++] = ch;
469 *has_newline = ch ? 1 : 0;
471 if (buffer) {
472 buffer[i] = 0;
475 return buffer;
478 static FindProgressStatus
479 check_find_events(Dlg_head *h)
481 Gpm_Event event;
482 int c;
484 c = get_event (&event, h->mouse_status == MOU_REPEAT, 0);
485 if (c != EV_NONE) {
486 dlg_process_event (h, c, &event);
487 if (h->ret_value == B_ENTER
488 || h->ret_value == B_CANCEL
489 || h->ret_value == B_AGAIN
490 || h->ret_value == B_PANELIZE) {
491 /* dialog terminated */
492 return FIND_ABORT;
494 if (!(h->flags & DLG_WANT_IDLE)) {
495 /* searching suspended */
496 return FIND_SUSPEND;
500 return FIND_CONT;
504 * search_content:
506 * Search the global (FIXME) regexp compiled content_pattern string in the
507 * DIRECTORY/FILE. It will add the found entries to the find listbox.
509 * returns 0 if do_search should look for another file
510 * 1 if do_search should exit and proceed to the event handler
512 static int
513 search_content (Dlg_head *h, const char *directory, const char *filename)
515 struct stat s;
516 char buffer [BUF_SMALL];
517 char *fname;
518 int file_fd;
519 int ret_val = 0;
521 fname = mhl_str_dir_plus_file (directory, filename);
523 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode)){
524 g_free (fname);
525 return 0;
528 file_fd = mc_open (fname, O_RDONLY);
529 g_free (fname);
531 if (file_fd == -1)
532 return 0;
534 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
536 status_update (buffer);
537 mc_refresh ();
539 enable_interrupt_key ();
540 got_interrupt ();
543 int line = 1;
544 int pos = 0;
545 int n_read = 0;
546 int has_newline;
547 char *p;
548 int found = 0;
549 typedef const char * (*search_fn) (const char *, const char *);
550 search_fn search_func;
552 if (resuming) {
553 /* We've been previously suspended, start from the previous position */
554 resuming = 0;
555 line = last_line;
556 pos = last_pos;
559 search_func = (case_sensitive) ? cstrstr : cstrcasestr;
561 while ((p = get_line_at (file_fd, buffer, &pos, &n_read, sizeof (buffer), &has_newline)) && (ret_val == 0)){
562 if (found == 0){ /* Search in binary line once */
563 if (find_regex_flag) {
564 if (regexec (r, p, 1, 0, 0) == 0){
565 g_free (p);
566 p = g_strdup_printf ("%d:%s", line, filename);
567 find_add_match (h, directory, p);
568 found = 1;
570 } else {
571 if (search_func (p, content_pattern) != NULL) {
572 char *match = g_strdup_printf("%d:%s", line, filename);
573 find_add_match (h, directory, match);
574 found = TRUE;
578 if (has_newline){
579 line++;
580 found = 0;
582 g_free (p);
584 if ((line & 0xff) == 0) {
585 FindProgressStatus res;
586 res = check_find_events(h);
587 switch (res) {
588 case FIND_ABORT:
589 stop_idle (h);
590 ret_val = 1;
591 break;
592 case FIND_SUSPEND:
593 resuming = 1;
594 last_line = line;
595 last_pos = pos;
596 ret_val = 1;
597 break;
598 default:
599 break;
605 disable_interrupt_key ();
606 mc_close (file_fd);
607 return ret_val;
610 static int
611 do_search (struct Dlg_head *h)
613 static struct dirent *dp = 0;
614 static DIR *dirp = 0;
615 static char *directory;
616 struct stat tmp_stat;
617 static int pos;
618 static int subdirs_left = 0;
620 if (!h) { /* someone forces me to close dirp */
621 if (dirp) {
622 mc_closedir (dirp);
623 dirp = 0;
625 g_free (directory);
626 directory = NULL;
627 dp = 0;
628 return 1;
630 do_search_begin:
631 while (!dp){
633 if (dirp){
634 mc_closedir (dirp);
635 dirp = 0;
638 while (!dirp){
639 char *tmp;
641 attrset (REVERSE_COLOR);
642 while (1) {
643 tmp = pop_directory ();
644 if (!tmp){
645 running = 0;
646 status_update (_("Finished"));
647 stop_idle (h);
648 return 0;
650 if (find_ignore_dirs){
651 int found;
652 char *temp_dir = g_strconcat (":", tmp, ":", (char *) NULL);
654 found = strstr (find_ignore_dirs, temp_dir) != 0;
655 g_free (temp_dir);
656 if (found)
657 g_free (tmp);
658 else
659 break;
660 } else
661 break;
664 g_free (directory);
665 directory = tmp;
667 if (verbose){
668 char buffer [BUF_SMALL];
670 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
671 name_trunc (directory, FIND2_X_USE));
672 status_update (buffer);
674 /* mc_stat should not be called after mc_opendir
675 because vfs_s_opendir modifies the st_nlink
677 if (!mc_stat (directory, &tmp_stat))
678 subdirs_left = tmp_stat.st_nlink - 2;
679 else
680 subdirs_left = 0;
681 /* Commented out as unnecessary
682 if (subdirs_left < 0)
683 subdirs_left = MAXINT;
685 dirp = mc_opendir (directory);
686 } /* while (!dirp) */
687 dp = mc_readdir (dirp);
688 } /* while (!dp) */
690 if (strcmp (dp->d_name, ".") == 0 ||
691 strcmp (dp->d_name, "..") == 0){
692 dp = mc_readdir (dirp);
693 return 1;
696 if (subdirs_left && find_recursively && directory) { /* Can directory be NULL ? */
697 char *tmp_name = mhl_str_dir_plus_file (directory, dp->d_name);
698 if (!mc_lstat (tmp_name, &tmp_stat)
699 && S_ISDIR (tmp_stat.st_mode)) {
700 push_directory (tmp_name);
701 subdirs_left--;
703 g_free (tmp_name);
706 if (regexp_match (find_pattern, dp->d_name, match_file)){
707 if (content_pattern) {
708 if (search_content (h, directory, dp->d_name)) {
709 return 1;
711 } else
712 find_add_match (h, directory, dp->d_name);
715 dp = mc_readdir (dirp);
717 /* Displays the nice dot */
718 count++;
719 if (!(count & 31)){
720 /* For nice updating */
721 const char *rotating_dash = "|/-\\";
723 if (verbose){
724 pos = (pos + 1) % 4;
725 attrset (DLG_NORMALC (h));
726 dlg_move (h, FIND2_Y-6, FIND2_X - 4);
727 addch (rotating_dash [pos]);
728 mc_refresh ();
730 } else
731 goto do_search_begin;
732 return 1;
735 static void
736 init_find_vars (void)
738 char *dir;
740 g_free (old_dir);
741 old_dir = 0;
742 count = 0;
743 matches = 0;
745 /* Remove all the items in the stack */
746 while ((dir = pop_directory ()) != NULL)
747 g_free (dir);
750 static char *
751 make_fullname (const char *dirname, const char *filename)
754 if (strcmp(dirname, ".") == 0 || strcmp(dirname, "."PATH_SEP_STR) == 0)
755 return g_strdup (filename);
756 if (strncmp(dirname, "."PATH_SEP_STR, 2) == 0)
757 return mhl_str_dir_plus_file (dirname + 2, filename);
758 return mhl_str_dir_plus_file (dirname, filename);
761 static void
762 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
764 char *fullname;
765 const char *filename;
766 int line;
768 if (content_pattern){
769 filename = strchr (file + 4, ':') + 1;
770 line = atoi (file + 4);
771 } else {
772 filename = file + 4;
773 line = 0;
776 fullname = make_fullname (dir, filename);
777 if (edit)
778 do_edit_at_line (fullname, line);
779 else
780 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
781 g_free (fullname);
784 static int
785 view_edit_currently_selected_file (int unparsed_view, int edit)
787 WLEntry *entry = find_list->current;
788 char *dir;
790 if (!entry)
791 return MSG_NOT_HANDLED;
793 dir = entry->data;
795 if (!entry->text || !dir)
796 return MSG_NOT_HANDLED;
798 find_do_view_edit (unparsed_view, edit, dir, entry->text);
799 return MSG_HANDLED;
802 static cb_ret_t
803 find_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
805 switch (msg) {
806 case DLG_KEY:
807 if (parm == KEY_F (3) || parm == KEY_F (13)) {
808 int unparsed_view = (parm == KEY_F (13));
809 return view_edit_currently_selected_file (unparsed_view, 0);
811 if (parm == KEY_F (4)) {
812 return view_edit_currently_selected_file (0, 1);
814 return MSG_NOT_HANDLED;
816 case DLG_IDLE:
817 do_search (h);
818 return MSG_HANDLED;
820 default:
821 return default_dlg_callback (h, msg, parm);
825 /* Handles the Stop/Start button in the find window */
826 static int
827 start_stop (int button)
829 (void) button;
831 running = is_start;
832 set_idle_proc (find_dlg, running);
833 is_start = !is_start;
835 status_update (is_start ? _("Stopped") : _("Searching"));
836 button_set_text (stop_button, fbuts [is_start].text);
838 return 0;
841 /* Handle view command, when invoked as a button */
842 static int
843 find_do_view_file (int button)
845 (void) button;
847 view_edit_currently_selected_file (0, 0);
848 return 0;
851 /* Handle edit command, when invoked as a button */
852 static int
853 find_do_edit_file (int button)
855 (void) button;
857 view_edit_currently_selected_file (0, 1);
858 return 0;
861 static void
862 setup_gui (void)
864 #ifdef ENABLE_NLS
865 static int i18n_flag = 0;
866 if (!i18n_flag) {
867 register int i = sizeof (fbuts) / sizeof (fbuts[0]);
868 while (i--)
869 fbuts[i].len = strlen (fbuts[i].text = _(fbuts[i].text)) + 3;
870 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
871 i18n_flag = 1;
873 #endif /* ENABLE_NLS */
876 * Dynamically place buttons centered within current window size
879 int l0 = max (fbuts[0].len, fbuts[1].len);
880 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
881 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
882 int r1, r2;
884 FIND2_X = COLS - 16;
886 /* Check, if both button rows fit within FIND2_X */
887 if (l1 + 9 > FIND2_X)
888 FIND2_X = l1 + 9;
889 if (l2 + 8 > FIND2_X)
890 FIND2_X = l2 + 8;
892 /* compute amount of space between buttons for each row */
893 r1 = (FIND2_X - 4 - l1) % 5;
894 l1 = (FIND2_X - 4 - l1) / 5;
895 r2 = (FIND2_X - 4 - l2) % 4;
896 l2 = (FIND2_X - 4 - l2) / 4;
898 /* ...and finally, place buttons */
899 fbuts[2].x = 2 + r1 / 2 + l1;
900 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
901 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
902 fbuts[4].x = fbuts[0].x + l0 + l1;
903 fbuts[5].x = 2 + r2 / 2 + l2;
904 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
905 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
908 find_dlg =
909 create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
910 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
912 add_widget (find_dlg,
913 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
914 fbuts[7].text, find_do_edit_file));
915 add_widget (find_dlg,
916 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
917 fbuts[6].text, find_do_view_file));
918 add_widget (find_dlg,
919 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE,
920 NORMAL_BUTTON, fbuts[5].text, 0));
922 add_widget (find_dlg,
923 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL,
924 NORMAL_BUTTON, fbuts[4].text, 0));
925 stop_button =
926 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
927 fbuts[0].text, start_stop);
928 add_widget (find_dlg, stop_button);
929 add_widget (find_dlg,
930 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN,
931 NORMAL_BUTTON, fbuts[3].text, 0));
932 add_widget (find_dlg,
933 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER,
934 DEFPUSH_BUTTON, fbuts[2].text, 0));
936 status_label = label_new (FIND2_Y - 6, 4, _("Searching"));
937 add_widget (find_dlg, status_label);
939 find_list =
940 listbox_new (2, 2, FIND2_X - 4, FIND2_Y - 9, 0);
941 add_widget (find_dlg, find_list);
944 static int
945 run_process (void)
947 resuming = 0;
948 set_idle_proc (find_dlg, 1);
949 run_dlg (find_dlg);
950 return find_dlg->ret_value;
953 static void
954 kill_gui (void)
956 set_idle_proc (find_dlg, 0);
957 destroy_dlg (find_dlg);
960 static int
961 find_file (char *start_dir, char *pattern, char *content, char **dirname,
962 char **filename)
964 int return_value = 0;
965 char *dir;
966 char *dir_tmp, *file_tmp;
968 setup_gui ();
970 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
971 find_pattern = pattern;
972 content_pattern = content;
974 init_find_vars ();
975 push_directory (start_dir);
977 return_value = run_process ();
979 /* Remove all the items in the stack */
980 while ((dir = pop_directory ()) != NULL)
981 g_free (dir);
983 get_list_info (&file_tmp, &dir_tmp);
985 if (dir_tmp)
986 *dirname = g_strdup (dir_tmp);
987 if (file_tmp)
988 *filename = g_strdup (file_tmp);
990 if (return_value == B_PANELIZE && *filename) {
991 int status, link_to_dir, stale_link;
992 int next_free = 0;
993 int i;
994 struct stat st;
995 WLEntry *entry = find_list->list;
996 dir_list *list = &current_panel->dir;
997 char *name;
999 for (i = 0; entry && i < find_list->count;
1000 entry = entry->next, i++) {
1001 const char *filename;
1003 if (!entry->text || !entry->data)
1004 continue;
1006 if (content_pattern)
1007 filename = strchr (entry->text + 4, ':') + 1;
1008 else
1009 filename = entry->text + 4;
1011 name = make_fullname (entry->data, filename);
1012 status =
1013 handle_path (list, name, &st, next_free, &link_to_dir,
1014 &stale_link);
1015 if (status == 0) {
1016 g_free (name);
1017 continue;
1019 if (status == -1) {
1020 g_free (name);
1021 break;
1024 /* don't add files more than once to the panel */
1025 if (content_pattern && next_free > 0) {
1026 if (strcmp (list->list[next_free - 1].fname, name) == 0) {
1027 g_free (name);
1028 continue;
1032 if (!next_free) /* first turn i.e clean old list */
1033 panel_clean_dir (current_panel);
1034 list->list[next_free].fnamelen = strlen (name);
1035 list->list[next_free].fname = name;
1036 list->list[next_free].f.marked = 0;
1037 list->list[next_free].f.link_to_dir = link_to_dir;
1038 list->list[next_free].f.stale_link = stale_link;
1039 list->list[next_free].f.dir_size_computed = 0;
1040 list->list[next_free].st = st;
1041 next_free++;
1042 if (!(next_free & 15))
1043 rotate_dash ();
1045 if (next_free) {
1046 current_panel->count = next_free;
1047 current_panel->is_panelized = 1;
1048 /* Done by panel_clean_dir a few lines above
1049 current_panel->dirs_marked = 0;
1050 current_panel->marked = 0;
1051 current_panel->total = 0;
1052 current_panel->top_file = 0;
1053 current_panel->selected = 0; */
1055 if (start_dir[0] == PATH_SEP) {
1056 strcpy (current_panel->cwd, PATH_SEP_STR);
1057 chdir (PATH_SEP_STR);
1062 kill_gui ();
1063 do_search (0); /* force do_search to release resources */
1064 g_free (old_dir);
1065 old_dir = 0;
1067 return return_value;
1070 void
1071 do_find (void)
1073 char *start_dir = NULL, *pattern = NULL, *content = NULL;
1074 char *filename, *dirname;
1075 int v, dir_and_file_set;
1076 regex_t rx; /* Compiled content_pattern to search inside files */
1078 for (r = &rx; find_parameters (&start_dir, &pattern, &content); r = &rx){
1080 dirname = filename = NULL;
1081 is_start = 0;
1082 v = find_file (start_dir, pattern, content, &dirname, &filename);
1083 g_free (start_dir);
1084 g_free (pattern);
1085 if (find_regex_flag && r)
1086 regfree (r);
1088 if (v == B_ENTER){
1089 if (dirname || filename){
1090 if (dirname){
1091 do_cd (dirname, cd_exact);
1092 if (filename)
1093 try_to_select (current_panel, filename + (content ?
1094 (strchr (filename + 4, ':') - filename + 1) : 4) );
1095 } else if (filename)
1096 do_cd (filename, cd_exact);
1097 select_item (current_panel);
1099 g_free (dirname);
1100 g_free (filename);
1101 break;
1103 g_free (content);
1104 dir_and_file_set = dirname && filename;
1105 g_free (dirname);
1106 g_free (filename);
1107 if (v == B_CANCEL)
1108 break;
1110 if (v == B_PANELIZE){
1111 if (dir_and_file_set){
1112 try_to_select (current_panel, NULL);
1113 panel_re_sort (current_panel);
1114 try_to_select (current_panel, NULL);
1116 break;