Update base version to 4.6.1.
[midnight-commander.git] / src / find.c
blobfcb452bdd46853f3b43e8037f626d5ce8a45cad3
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21 #include <config.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include <sys/stat.h>
30 #include "global.h"
31 #include "tty.h"
32 #include "win.h"
33 #include "color.h"
34 #include "setup.h"
35 #include "find.h"
37 /* Dialog manager and widgets */
38 #include "dialog.h"
39 #include "widget.h"
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 "key.h"
49 /* Size of the find parameters window */
50 #define FIND_Y 15
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 typedef enum {
69 FIND_CONT,
70 FIND_SUSPEND,
71 FIND_ABORT
72 } FindProgressStatus;
74 /* List of directories to be ignored, separated by ':' */
75 char *find_ignore_dirs = 0;
77 static WInput *in_start; /* Start path */
78 static WInput *in_name; /* Pattern to search */
79 static WInput *in_with; /* Text inside filename */
80 static WCheck *case_sense; /* "case sensitive" checkbox */
81 static WCheck *find_regex_cbox; /* [x] find regular expression */
83 static int running = 0; /* nice flag */
84 static char *find_pattern; /* Pattern to search */
85 static char *content_pattern; /* pattern to search inside files; if
86 find_regex_flag is true, it contains the
87 regex pattern, else the search string. */
88 static int count; /* Number of files displayed */
89 static int matches; /* Number of matches */
90 static int is_start; /* Status of the start/stop toggle button */
91 static char *old_dir;
93 /* Where did we stop */
94 static int resuming;
95 static int last_line;
96 static int last_pos;
98 static Dlg_head *find_dlg; /* The dialog */
100 static WButton *stop_button; /* pointer to the stop button */
101 static WLabel *status_label; /* Finished, Searching etc. */
102 static WListbox *find_list; /* Listbox with the file list */
104 /* This keeps track of the directory stack */
105 typedef struct dir_stack {
106 char *name;
107 struct dir_stack *prev;
108 } dir_stack ;
110 static dir_stack *dir_stack_base = 0;
112 static struct {
113 const char* text;
114 int len; /* length including space and brackets */
115 int x;
116 } fbuts [] = {
117 { N_("&Suspend"), 11, 29 },
118 { N_("Con&tinue"), 12, 29 },
119 { N_("&Chdir"), 11, 3 },
120 { N_("&Again"), 9, 17 },
121 { N_("&Quit"), 8, 43 },
122 { N_("Pane&lize"), 12, 3 },
123 { N_("&View - F3"), 13, 20 },
124 { N_("&Edit - F4"), 13, 38 }
127 static inline char * add_to_list (const char *text, void *data) {
128 return listbox_add_item (find_list, 0, 0, text, data);
130 static inline void stop_idle (void *data) {
131 set_idle_proc (data, 0);
133 static inline void status_update (const char *text) {
134 label_set_text (status_label, text);
136 static void get_list_info (char **file, char **dir) {
137 listbox_get_current (find_list, file, dir);
140 /* FIXME: r should be local variable */
141 static regex_t *r; /* Pointer to compiled content_pattern */
143 static int case_sensitive = 1;
144 static gboolean find_regex_flag = TRUE;
145 static int find_recursively = 1;
148 * Callback for the parameter dialog.
149 * Validate regex, prevent closing the dialog if it's invalid.
151 static cb_ret_t
152 find_parm_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
154 int flags;
156 switch (msg) {
157 case DLG_VALIDATE:
158 if ((h->ret_value != B_ENTER) || !in_with->buffer[0]
159 || !(find_regex_cbox->state & C_BOOL))
160 return MSG_HANDLED;
162 flags = REG_EXTENDED | REG_NOSUB;
164 if (!(case_sense->state & C_BOOL))
165 flags |= REG_ICASE;
167 if (regcomp (r, in_with->buffer, flags)) {
168 message (1, MSG_ERROR, _(" Malformed regular expression "));
169 dlg_select_widget (in_with);
170 h->running = 1; /* Don't stop the dialog */
172 return MSG_HANDLED;
174 default:
175 return default_dlg_callback (h, msg, parm);
180 * find_parameters: gets information from the user
182 * If the return value is true, then the following holds:
184 * START_DIR and PATTERN are pointers to char * and upon return they
185 * contain the information provided by the user.
187 * CONTENT holds a strdup of the contents specified by the user if he
188 * asked for them or 0 if not (note, this is different from the
189 * behavior for the other two parameters.
192 static int
193 find_parameters (char **start_dir, char **pattern, char **content)
195 int return_value;
196 char *temp_dir;
197 static const char *case_label = N_("case &Sensitive");
198 static const char *recurs_label = N_("find Re&cursively");
200 WCheck *recursively_cbox;
202 static char *in_contents = NULL;
203 static char *in_start_dir = NULL;
204 static char *in_start_name = NULL;
206 static const char *labs[] =
207 { N_("Start at:"), N_("Filename:"), N_("Content: ") };
208 static const char *buts[] = { N_("&OK"), N_("&Tree"), N_("&Cancel") };
209 static int ilen = 30, istart = 14;
210 static int b0 = 3, b1 = 16, b2 = 36;
212 #ifdef ENABLE_NLS
213 static int i18n_flag = 0;
215 if (!i18n_flag) {
216 register int i = sizeof (labs) / sizeof (labs[0]);
217 int l1, maxlen = 0;
219 while (i--) {
220 l1 = strlen (labs[i] = _(labs[i]));
221 if (l1 > maxlen)
222 maxlen = l1;
224 i = maxlen + ilen + 7;
225 if (i > FIND_X)
226 FIND_X = i;
228 for (i = sizeof (buts) / sizeof (buts[0]), l1 = 0; i--;) {
229 l1 += strlen (buts[i] = _(buts[i]));
231 l1 += 21;
232 if (l1 > FIND_X)
233 FIND_X = l1;
235 ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
236 istart = FIND_X - 3 - ilen;
238 b1 = b0 + strlen (buts[0]) + 7;
239 b2 = FIND_X - (strlen (buts[2]) + 6);
241 i18n_flag = 1;
242 case_label = _(case_label);
243 recurs_label = _(recurs_label);
245 #endif /* ENABLE_NLS */
247 find_par_start:
248 if (!in_start_dir)
249 in_start_dir = g_strdup (".");
250 if (!in_start_name)
251 in_start_name = g_strdup (easy_patterns ? "*" : ".");
252 if (!in_contents)
253 in_contents = g_strdup ("");
255 find_dlg =
256 create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
257 find_parm_callback, "[Find File]", _("Find File"),
258 DLG_CENTER | DLG_REVERSE);
260 add_widget (find_dlg,
261 button_new (12, b2, B_CANCEL, NORMAL_BUTTON, buts[2], 0));
262 add_widget (find_dlg,
263 button_new (12, b1, B_TREE, NORMAL_BUTTON, buts[1], 0));
264 add_widget (find_dlg,
265 button_new (12, b0, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
267 recursively_cbox =
268 check_new (6, istart, find_recursively, recurs_label);
270 find_regex_cbox = check_new (10, istart, find_regex_flag, _("&Regular expression"));
271 add_widget (find_dlg, find_regex_cbox);
273 case_sense = check_new (9, istart, case_sensitive, case_label);
274 add_widget (find_dlg, case_sense);
276 in_with =
277 input_new (8, istart, INPUT_COLOR, ilen, in_contents, "content");
278 add_widget (find_dlg, in_with);
280 add_widget (find_dlg, recursively_cbox);
281 in_name =
282 input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name");
283 add_widget (find_dlg, in_name);
285 in_start =
286 input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start");
287 add_widget (find_dlg, in_start);
289 add_widget (find_dlg, label_new (8, 3, labs[2]));
290 add_widget (find_dlg, label_new (5, 3, labs[1]));
291 add_widget (find_dlg, label_new (3, 3, labs[0]));
293 dlg_select_widget (in_name);
295 run_dlg (find_dlg);
297 switch (find_dlg->ret_value) {
298 case B_CANCEL:
299 return_value = 0;
300 break;
302 case B_TREE:
303 temp_dir = g_strdup (in_start->buffer);
304 case_sensitive = case_sense->state & C_BOOL;
305 find_regex_flag = find_regex_cbox->state & C_BOOL;
306 find_recursively = recursively_cbox->state & C_BOOL;
307 destroy_dlg (find_dlg);
308 g_free (in_start_dir);
309 if (strcmp (temp_dir, ".") == 0) {
310 g_free (temp_dir);
311 temp_dir = g_strdup (current_panel->cwd);
313 in_start_dir = tree_box (temp_dir);
314 if (in_start_dir)
315 g_free (temp_dir);
316 else
317 in_start_dir = temp_dir;
318 /* Warning: Dreadful goto */
319 goto find_par_start;
320 break;
322 default:
323 g_free (in_contents);
324 if (in_with->buffer[0]) {
325 *content = g_strdup (in_with->buffer);
326 in_contents = g_strdup (*content);
327 } else {
328 *content = in_contents = NULL;
329 r = 0;
332 case_sensitive = case_sense->state & C_BOOL;
333 find_regex_flag = find_regex_cbox->state & C_BOOL;
334 find_recursively = recursively_cbox->state & C_BOOL;
335 return_value = 1;
336 *start_dir = g_strdup (in_start->buffer);
337 *pattern = g_strdup (in_name->buffer);
339 g_free (in_start_dir);
340 in_start_dir = g_strdup (*start_dir);
341 g_free (in_start_name);
342 in_start_name = g_strdup (*pattern);
345 destroy_dlg (find_dlg);
347 return return_value;
350 static void
351 push_directory (const char *dir)
353 dir_stack *new;
355 new = g_new (dir_stack, 1);
356 new->name = concat_dir_and_file (dir, "");
357 new->prev = dir_stack_base;
358 dir_stack_base = new;
361 static char*
362 pop_directory (void)
364 char *name;
365 dir_stack *next;
367 if (dir_stack_base){
368 name = dir_stack_base->name;
369 next = dir_stack_base->prev;
370 g_free (dir_stack_base);
371 dir_stack_base = next;
372 return name;
373 } else
374 return 0;
377 static void
378 insert_file (const char *dir, const char *file)
380 char *tmp_name;
381 static char *dirname;
383 while (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
384 dir++;
386 if (old_dir){
387 if (strcmp (old_dir, dir)){
388 g_free (old_dir);
389 old_dir = g_strdup (dir);
390 dirname = add_to_list (dir, NULL);
392 } else {
393 old_dir = g_strdup (dir);
394 dirname = add_to_list (dir, NULL);
397 tmp_name = g_strconcat (" ", file, (char *) NULL);
398 add_to_list (tmp_name, dirname);
399 g_free (tmp_name);
402 static void
403 find_add_match (Dlg_head *h, const char *dir, const char *file)
405 int p = ++matches & 7;
407 (void) h;
409 insert_file (dir, file);
411 /* Scroll nicely */
412 if (!p)
413 listbox_select_last (find_list, 1);
414 else
415 listbox_select_last (find_list, 0);
416 /* Updates the current listing */
417 send_message (&find_list->widget, WIDGET_DRAW, 0);
418 if (p == 7)
419 mc_refresh ();
423 * get_line_at:
425 * Returns malloced null-terminated line from file file_fd.
426 * Input is buffered in buf_size long buffer.
427 * Current pos in buf is stored in pos.
428 * n_read - number of read chars.
429 * has_newline - is there newline ?
431 static char *
432 get_line_at (int file_fd, char *buf, int *pos, int *n_read, int buf_size,
433 int *has_newline)
435 char *buffer = 0;
436 int buffer_size = 0;
437 char ch = 0;
438 int i = 0;
440 for (;;) {
441 if (*pos >= *n_read) {
442 *pos = 0;
443 if ((*n_read = mc_read (file_fd, buf, buf_size)) <= 0)
444 break;
447 ch = buf[(*pos)++];
448 if (ch == 0) {
449 /* skip possible leading zero(s) */
450 if (i == 0)
451 continue;
452 else
453 break;
456 if (i >= buffer_size - 1) {
457 buffer = g_realloc (buffer, buffer_size += 80);
459 /* Strip newline */
460 if (ch == '\n')
461 break;
463 buffer[i++] = ch;
466 *has_newline = ch ? 1 : 0;
468 if (buffer) {
469 buffer[i] = 0;
472 return buffer;
475 static FindProgressStatus
476 check_find_events(Dlg_head *h)
478 Gpm_Event event;
479 int c;
481 c = get_event (&event, h->mouse_status == MOU_REPEAT, 0);
482 if (c != EV_NONE) {
483 dlg_process_event (h, c, &event);
484 if (h->ret_value == B_ENTER
485 || h->ret_value == B_CANCEL
486 || h->ret_value == B_AGAIN
487 || h->ret_value == B_PANELIZE) {
488 /* dialog terminated */
489 return FIND_ABORT;
491 if (!(h->flags & DLG_WANT_IDLE)) {
492 /* searching suspended */
493 return FIND_SUSPEND;
497 return FIND_CONT;
501 * search_content:
503 * Search the global (FIXME) regexp compiled content_pattern string in the
504 * DIRECTORY/FILE. It will add the found entries to the find listbox.
506 * returns 0 if do_search should look for another file
507 * 1 if do_search should exit and proceed to the event handler
509 static int
510 search_content (Dlg_head *h, const char *directory, const char *filename)
512 struct stat s;
513 char buffer [BUF_SMALL];
514 char *fname;
515 int file_fd;
516 int ret_val = 0;
518 fname = concat_dir_and_file (directory, filename);
520 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode)){
521 g_free (fname);
522 return 0;
525 file_fd = mc_open (fname, O_RDONLY);
526 g_free (fname);
528 if (file_fd == -1)
529 return 0;
531 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
533 status_update (buffer);
534 mc_refresh ();
536 enable_interrupt_key ();
537 got_interrupt ();
540 int line = 1;
541 int pos = 0;
542 int n_read = 0;
543 int has_newline;
544 char *p;
545 int found = 0;
546 typedef const char * (*search_fn) (const char *, const char *);
547 search_fn search_func;
549 if (resuming) {
550 /* We've been previously suspended, start from the previous position */
551 resuming = 0;
552 line = last_line;
553 pos = last_pos;
556 search_func = (case_sensitive) ? cstrstr : cstrcasestr;
558 while ((p = get_line_at (file_fd, buffer, &pos, &n_read, sizeof (buffer), &has_newline)) && (ret_val == 0)){
559 if (found == 0){ /* Search in binary line once */
560 if (find_regex_flag) {
561 if (regexec (r, p, 1, 0, 0) == 0){
562 g_free (p);
563 p = g_strdup_printf ("%d:%s", line, filename);
564 find_add_match (h, directory, p);
565 found = 1;
567 } else {
568 if (search_func (p, content_pattern) != NULL) {
569 char *match = g_strdup_printf("%d:%s", line, filename);
570 find_add_match (h, directory, match);
571 found = TRUE;
575 if (has_newline){
576 line++;
577 found = 0;
579 g_free (p);
581 if ((line & 0xff) == 0) {
582 FindProgressStatus res;
583 res = check_find_events(h);
584 switch (res) {
585 case FIND_ABORT:
586 stop_idle (h);
587 ret_val = 1;
588 break;
589 case FIND_SUSPEND:
590 resuming = 1;
591 last_line = line;
592 last_pos = pos;
593 ret_val = 1;
594 break;
595 default:
596 break;
602 disable_interrupt_key ();
603 mc_close (file_fd);
604 return ret_val;
607 static int
608 do_search (struct Dlg_head *h)
610 static struct dirent *dp = 0;
611 static DIR *dirp = 0;
612 static char *directory;
613 struct stat tmp_stat;
614 static int pos;
615 static int subdirs_left = 0;
617 if (!h) { /* someone forces me to close dirp */
618 if (dirp) {
619 mc_closedir (dirp);
620 dirp = 0;
622 g_free (directory);
623 directory = NULL;
624 dp = 0;
625 return 1;
627 do_search_begin:
628 while (!dp){
630 if (dirp){
631 mc_closedir (dirp);
632 dirp = 0;
635 while (!dirp){
636 char *tmp;
638 attrset (REVERSE_COLOR);
639 while (1) {
640 tmp = pop_directory ();
641 if (!tmp){
642 running = 0;
643 status_update (_("Finished"));
644 stop_idle (h);
645 return 0;
647 if (find_ignore_dirs){
648 int found;
649 char *temp_dir = g_strconcat (":", tmp, ":", (char *) NULL);
651 found = strstr (find_ignore_dirs, temp_dir) != 0;
652 g_free (temp_dir);
653 if (found)
654 g_free (tmp);
655 else
656 break;
657 } else
658 break;
661 g_free (directory);
662 directory = tmp;
664 if (verbose){
665 char buffer [BUF_SMALL];
667 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
668 name_trunc (directory, FIND2_X_USE));
669 status_update (buffer);
671 /* mc_stat should not be called after mc_opendir
672 because vfs_s_opendir modifies the st_nlink
674 if (!mc_stat (directory, &tmp_stat))
675 subdirs_left = tmp_stat.st_nlink - 2;
676 else
677 subdirs_left = 0;
678 /* Commented out as unnecessary
679 if (subdirs_left < 0)
680 subdirs_left = MAXINT;
682 dirp = mc_opendir (directory);
683 } /* while (!dirp) */
684 dp = mc_readdir (dirp);
685 } /* while (!dp) */
687 if (strcmp (dp->d_name, ".") == 0 ||
688 strcmp (dp->d_name, "..") == 0){
689 dp = mc_readdir (dirp);
690 return 1;
693 if (subdirs_left && find_recursively && directory) { /* Can directory be NULL ? */
694 char *tmp_name = concat_dir_and_file (directory, dp->d_name);
695 if (!mc_lstat (tmp_name, &tmp_stat)
696 && S_ISDIR (tmp_stat.st_mode)) {
697 push_directory (tmp_name);
698 subdirs_left--;
700 g_free (tmp_name);
703 if (regexp_match (find_pattern, dp->d_name, match_file)){
704 if (content_pattern) {
705 if (search_content (h, directory, dp->d_name)) {
706 return 1;
708 } else
709 find_add_match (h, directory, dp->d_name);
712 dp = mc_readdir (dirp);
714 /* Displays the nice dot */
715 count++;
716 if (!(count & 31)){
717 /* For nice updating */
718 const char *rotating_dash = "|/-\\";
720 if (verbose){
721 pos = (pos + 1) % 4;
722 attrset (DLG_NORMALC (h));
723 dlg_move (h, FIND2_Y-6, FIND2_X - 4);
724 addch (rotating_dash [pos]);
725 mc_refresh ();
727 } else
728 goto do_search_begin;
729 return 1;
732 static void
733 init_find_vars (void)
735 char *dir;
737 g_free (old_dir);
738 old_dir = 0;
739 count = 0;
740 matches = 0;
742 /* Remove all the items in the stack */
743 while ((dir = pop_directory ()) != NULL)
744 g_free (dir);
747 static void
748 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
750 char *fullname;
751 const char *filename;
752 int line;
754 if (content_pattern){
755 filename = strchr (file + 4, ':') + 1;
756 line = atoi (file + 4);
757 } else {
758 filename = file + 4;
759 line = 0;
761 if (dir [0] == '.' && dir [1] == 0)
762 fullname = g_strdup (filename);
763 else if (dir [0] == '.' && dir [1] == PATH_SEP)
764 fullname = concat_dir_and_file (dir+2, filename);
765 else
766 fullname = concat_dir_and_file (dir, filename);
768 if (edit)
769 do_edit_at_line (fullname, line);
770 else
771 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
772 g_free (fullname);
775 static int
776 view_edit_currently_selected_file (int unparsed_view, int edit)
778 WLEntry *entry = find_list->current;
779 char *dir;
781 if (!entry)
782 return MSG_NOT_HANDLED;
784 dir = entry->data;
786 if (!entry->text || !dir)
787 return MSG_NOT_HANDLED;
789 find_do_view_edit (unparsed_view, edit, dir, entry->text);
790 return MSG_HANDLED;
793 static cb_ret_t
794 find_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
796 switch (msg) {
797 case DLG_KEY:
798 if (parm == KEY_F (3) || parm == KEY_F (13)) {
799 int unparsed_view = (parm == KEY_F (13));
800 return view_edit_currently_selected_file (unparsed_view, 0);
802 if (parm == KEY_F (4)) {
803 return view_edit_currently_selected_file (0, 1);
805 return MSG_NOT_HANDLED;
807 case DLG_IDLE:
808 do_search (h);
809 return MSG_HANDLED;
811 default:
812 return default_dlg_callback (h, msg, parm);
816 /* Handles the Stop/Start button in the find window */
817 static int
818 start_stop (int button)
820 (void) button;
822 running = is_start;
823 set_idle_proc (find_dlg, running);
824 is_start = !is_start;
826 status_update (is_start ? _("Stopped") : _("Searching"));
827 button_set_text (stop_button, fbuts [is_start].text);
829 return 0;
832 /* Handle view command, when invoked as a button */
833 static int
834 find_do_view_file (int button)
836 (void) button;
838 view_edit_currently_selected_file (0, 0);
839 return 0;
842 /* Handle edit command, when invoked as a button */
843 static int
844 find_do_edit_file (int button)
846 (void) button;
848 view_edit_currently_selected_file (0, 1);
849 return 0;
852 static void
853 setup_gui (void)
855 #ifdef ENABLE_NLS
856 static int i18n_flag = 0;
857 if (!i18n_flag) {
858 register int i = sizeof (fbuts) / sizeof (fbuts[0]);
859 while (i--)
860 fbuts[i].len = strlen (fbuts[i].text = _(fbuts[i].text)) + 3;
861 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
862 i18n_flag = 1;
864 #endif /* ENABLE_NLS */
867 * Dynamically place buttons centered within current window size
870 int l0 = max (fbuts[0].len, fbuts[1].len);
871 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
872 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
873 int r1, r2;
875 FIND2_X = COLS - 16;
877 /* Check, if both button rows fit within FIND2_X */
878 if (l1 + 9 > FIND2_X)
879 FIND2_X = l1 + 9;
880 if (l2 + 8 > FIND2_X)
881 FIND2_X = l2 + 8;
883 /* compute amount of space between buttons for each row */
884 r1 = (FIND2_X - 4 - l1) % 5;
885 l1 = (FIND2_X - 4 - l1) / 5;
886 r2 = (FIND2_X - 4 - l2) % 4;
887 l2 = (FIND2_X - 4 - l2) / 4;
889 /* ...and finally, place buttons */
890 fbuts[2].x = 2 + r1 / 2 + l1;
891 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
892 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
893 fbuts[4].x = fbuts[0].x + l0 + l1;
894 fbuts[5].x = 2 + r2 / 2 + l2;
895 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
896 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
899 find_dlg =
900 create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
901 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
903 add_widget (find_dlg,
904 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
905 fbuts[7].text, find_do_edit_file));
906 add_widget (find_dlg,
907 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
908 fbuts[6].text, find_do_view_file));
909 add_widget (find_dlg,
910 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE,
911 NORMAL_BUTTON, fbuts[5].text, 0));
913 add_widget (find_dlg,
914 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL,
915 NORMAL_BUTTON, fbuts[4].text, 0));
916 stop_button =
917 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
918 fbuts[0].text, start_stop);
919 add_widget (find_dlg, stop_button);
920 add_widget (find_dlg,
921 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN,
922 NORMAL_BUTTON, fbuts[3].text, 0));
923 add_widget (find_dlg,
924 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER,
925 DEFPUSH_BUTTON, fbuts[2].text, 0));
927 status_label = label_new (FIND2_Y - 6, 4, _("Searching"));
928 add_widget (find_dlg, status_label);
930 find_list =
931 listbox_new (2, 2, FIND2_X - 4, FIND2_Y - 9, 0);
932 add_widget (find_dlg, find_list);
935 static int
936 run_process (void)
938 resuming = 0;
939 set_idle_proc (find_dlg, 1);
940 run_dlg (find_dlg);
941 return find_dlg->ret_value;
944 static void
945 kill_gui (void)
947 set_idle_proc (find_dlg, 0);
948 destroy_dlg (find_dlg);
951 static int
952 find_file (char *start_dir, char *pattern, char *content, char **dirname,
953 char **filename)
955 int return_value = 0;
956 char *dir;
957 char *dir_tmp, *file_tmp;
959 setup_gui ();
961 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
962 find_pattern = pattern;
963 content_pattern = content;
965 init_find_vars ();
966 push_directory (start_dir);
968 return_value = run_process ();
970 /* Remove all the items in the stack */
971 while ((dir = pop_directory ()) != NULL)
972 g_free (dir);
974 get_list_info (&file_tmp, &dir_tmp);
976 if (dir_tmp)
977 *dirname = g_strdup (dir_tmp);
978 if (file_tmp)
979 *filename = g_strdup (file_tmp);
981 if (return_value == B_PANELIZE && *filename) {
982 int status, link_to_dir, stale_link;
983 int next_free = 0;
984 int i;
985 struct stat st;
986 WLEntry *entry = find_list->list;
987 dir_list *list = &current_panel->dir;
988 char *dir, *name;
990 for (i = 0; entry && i < find_list->count;
991 entry = entry->next, i++) {
992 const char *filename;
994 if (!entry->text || !entry->data)
995 continue;
997 if (content_pattern)
998 filename = strchr (entry->text + 4, ':') + 1;
999 else
1000 filename = entry->text + 4;
1002 dir = entry->data;
1003 if (dir[0] == '.' && dir[1] == 0)
1004 name = g_strdup (filename);
1005 else if (dir[0] == '.' && dir[1] == PATH_SEP)
1006 name = concat_dir_and_file (dir + 2, filename);
1007 else
1008 name = concat_dir_and_file (dir, filename);
1009 status =
1010 handle_path (list, name, &st, next_free, &link_to_dir,
1011 &stale_link);
1012 if (status == 0) {
1013 g_free (name);
1014 continue;
1016 if (status == -1) {
1017 g_free (name);
1018 break;
1021 /* don't add files more than once to the panel */
1022 if (content_pattern && next_free > 0) {
1023 if (strcmp (list->list[next_free - 1].fname, name) == 0) {
1024 g_free (name);
1025 continue;
1029 if (!next_free) /* first turn i.e clean old list */
1030 panel_clean_dir (current_panel);
1031 list->list[next_free].fnamelen = strlen (name);
1032 list->list[next_free].fname = name;
1033 list->list[next_free].f.marked = 0;
1034 list->list[next_free].f.link_to_dir = link_to_dir;
1035 list->list[next_free].f.stale_link = stale_link;
1036 list->list[next_free].f.dir_size_computed = 0;
1037 list->list[next_free].st = st;
1038 next_free++;
1039 if (!(next_free & 15))
1040 rotate_dash ();
1042 if (next_free) {
1043 current_panel->count = next_free;
1044 current_panel->is_panelized = 1;
1045 /* Done by panel_clean_dir a few lines above
1046 current_panel->dirs_marked = 0;
1047 current_panel->marked = 0;
1048 current_panel->total = 0;
1049 current_panel->top_file = 0;
1050 current_panel->selected = 0; */
1052 if (start_dir[0] == PATH_SEP) {
1053 strcpy (current_panel->cwd, PATH_SEP_STR);
1054 chdir (PATH_SEP_STR);
1059 kill_gui ();
1060 do_search (0); /* force do_search to release resources */
1061 g_free (old_dir);
1062 old_dir = 0;
1064 return return_value;
1067 void
1068 do_find (void)
1070 char *start_dir = NULL, *pattern = NULL, *content = NULL;
1071 char *filename, *dirname;
1072 int v, dir_and_file_set;
1073 regex_t rx; /* Compiled content_pattern to search inside files */
1075 for (r = &rx; find_parameters (&start_dir, &pattern, &content); r = &rx){
1077 dirname = filename = NULL;
1078 is_start = 0;
1079 v = find_file (start_dir, pattern, content, &dirname, &filename);
1080 g_free (start_dir);
1081 g_free (pattern);
1082 if (find_regex_flag && r)
1083 regfree (r);
1085 if (v == B_ENTER){
1086 if (dirname || filename){
1087 if (dirname){
1088 do_cd (dirname, cd_exact);
1089 if (filename)
1090 try_to_select (current_panel, filename + (content ?
1091 (strchr (filename + 4, ':') - filename + 1) : 4) );
1092 } else if (filename)
1093 do_cd (filename, cd_exact);
1094 select_item (current_panel);
1096 g_free (dirname);
1097 g_free (filename);
1098 break;
1100 g_free (content);
1101 dir_and_file_set = dirname && filename;
1102 g_free (dirname);
1103 g_free (filename);
1104 if (v == B_CANCEL)
1105 break;
1107 if (v == B_PANELIZE){
1108 if (dir_and_file_set){
1109 try_to_select (current_panel, NULL);
1110 panel_re_sort (current_panel);
1112 break;