Forgot to remove some more .s strings and do a rename in order to prevent compiler...
[midnight-commander.git] / src / find.c
blob517a219c4ce8579ecfadca9e43385780bc7a6a79
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/memory.h>
32 #include <mhl/string.h>
34 #include "global.h"
35 #include "tty.h"
36 #include "win.h"
37 #include "color.h"
38 #include "setup.h"
39 #include "find.h"
41 /* Dialog manager and widgets */
42 #include "dialog.h"
43 #include "widget.h"
45 #include "dir.h"
46 #include "panel.h" /* current_panel */
47 #include "main.h" /* do_cd, try_to_select */
48 #include "wtools.h"
49 #include "cmd.h" /* view_file_at_line */
50 #include "boxes.h"
51 #include "key.h"
53 /* Size of the find parameters window */
54 #define FIND_Y 15
55 static int FIND_X = 50;
57 /* Size of the find window */
58 #define FIND2_Y (LINES - 4)
60 static int FIND2_X = 64;
61 #define FIND2_X_USE (FIND2_X - 20)
63 /* A couple of extra messages we need */
64 enum {
65 B_STOP = B_USER + 1,
66 B_AGAIN,
67 B_PANELIZE,
68 B_TREE,
69 B_VIEW
72 typedef enum {
73 FIND_CONT,
74 FIND_SUSPEND,
75 FIND_ABORT
76 } FindProgressStatus;
78 /* List of directories to be ignored, separated by ':' */
79 char *find_ignore_dirs = 0;
81 static WInput *in_start; /* Start path */
82 static WInput *in_name; /* Pattern to search */
83 static WInput *in_with; /* Text inside filename */
84 static WCheck *case_sense; /* "case sensitive" checkbox */
85 static WCheck *find_regex_cbox; /* [x] find regular expression */
87 static int running = 0; /* nice flag */
88 static char *find_pattern; /* Pattern to search */
89 static char *content_pattern; /* pattern to search inside files; if
90 find_regex_flag is true, it contains the
91 regex pattern, else the search string. */
92 static int count; /* Number of files displayed */
93 static int matches; /* Number of matches */
94 static int is_start; /* Status of the start/stop toggle button */
95 static char *old_dir;
97 /* Where did we stop */
98 static int resuming;
99 static int last_line;
100 static int last_pos;
102 static Dlg_head *find_dlg; /* The dialog */
104 static WButton *stop_button; /* pointer to the stop button */
105 static WLabel *status_label; /* Finished, Searching etc. */
106 static WListbox *find_list; /* Listbox with the file list */
108 /* This keeps track of the directory stack */
109 typedef struct dir_stack {
110 char *name;
111 struct dir_stack *prev;
112 } dir_stack ;
114 static dir_stack *dir_stack_base = 0;
116 static struct {
117 const char* text;
118 int len; /* length including space and brackets */
119 int x;
120 } fbuts [] = {
121 { N_("&Suspend"), 11, 29 },
122 { N_("Con&tinue"), 12, 29 },
123 { N_("&Chdir"), 11, 3 },
124 { N_("&Again"), 9, 17 },
125 { N_("&Quit"), 8, 43 },
126 { N_("Pane&lize"), 12, 3 },
127 { N_("&View - F3"), 13, 20 },
128 { N_("&Edit - F4"), 13, 38 }
131 static inline char * add_to_list (const char *text, void *data) {
132 return listbox_add_item (find_list, 0, 0, text, data);
134 static inline void stop_idle (void *data) {
135 set_idle_proc (data, 0);
137 static inline void status_update (const char *text) {
138 label_set_text (status_label, text);
140 static void get_list_info (char **file, char **dir) {
141 listbox_get_current (find_list, file, dir);
144 /* FIXME: r should be local variable */
145 static regex_t *r; /* Pointer to compiled content_pattern */
147 static int case_sensitive = 1;
148 static gboolean find_regex_flag = TRUE;
149 static int find_recursively = 1;
152 * Callback for the parameter dialog.
153 * Validate regex, prevent closing the dialog if it's invalid.
155 static cb_ret_t
156 find_parm_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
158 int flags;
160 switch (msg) {
161 case DLG_VALIDATE:
162 if ((h->ret_value != B_ENTER) || !in_with->buffer[0]
163 || !(find_regex_cbox->state & C_BOOL))
164 return MSG_HANDLED;
166 flags = REG_EXTENDED | REG_NOSUB;
168 if (!(case_sense->state & C_BOOL))
169 flags |= REG_ICASE;
171 if (regcomp (r, in_with->buffer, flags)) {
172 message (D_ERROR, MSG_ERROR, _(" Malformed regular expression "));
173 dlg_select_widget (in_with);
174 h->running = 1; /* Don't stop the dialog */
176 return MSG_HANDLED;
178 default:
179 return default_dlg_callback (h, msg, parm);
184 * find_parameters: gets information from the user
186 * If the return value is true, then the following holds:
188 * START_DIR and PATTERN are pointers to char * and upon return they
189 * contain the information provided by the user.
191 * CONTENT holds a strdup of the contents specified by the user if he
192 * asked for them or 0 if not (note, this is different from the
193 * behavior for the other two parameters.
196 static int
197 find_parameters (char **start_dir, char **pattern, char **content)
199 int return_value;
200 char *temp_dir;
201 static const char *case_label = N_("case &Sensitive");
202 static const char *recurs_label = N_("&Find recursively");
204 WCheck *recursively_cbox;
206 static char *in_contents = NULL;
207 static char *in_start_dir = NULL;
208 static char *in_start_name = NULL;
210 static const char *labs[] =
211 { N_("Start at:"), N_("Filename:"), N_("Content: ") };
212 static const char *buts[] = { N_("&OK"), N_("&Tree"), N_("&Cancel") };
213 static int ilen = 30, istart = 14;
214 static int b0 = 3, b1 = 16, b2 = 36;
216 #ifdef ENABLE_NLS
217 static int i18n_flag = 0;
219 if (!i18n_flag) {
220 register int i = sizeof (labs) / sizeof (labs[0]);
221 int l1, maxlen = 0;
223 while (i--) {
224 l1 = strlen (labs[i] = _(labs[i]));
225 if (l1 > maxlen)
226 maxlen = l1;
228 i = maxlen + ilen + 7;
229 if (i > FIND_X)
230 FIND_X = i;
232 for (i = sizeof (buts) / sizeof (buts[0]), l1 = 0; i--;) {
233 l1 += strlen (buts[i] = _(buts[i]));
235 l1 += 21;
236 if (l1 > FIND_X)
237 FIND_X = l1;
239 ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
240 istart = FIND_X - 3 - ilen;
242 b1 = b0 + strlen (buts[0]) + 7;
243 b2 = FIND_X - (strlen (buts[2]) + 6);
245 i18n_flag = 1;
246 case_label = _(case_label);
247 recurs_label = _(recurs_label);
249 #endif /* ENABLE_NLS */
251 find_par_start:
252 if (!in_start_dir)
253 in_start_dir = g_strdup (".");
254 if (!in_start_name)
255 in_start_name = g_strdup (easy_patterns ? "*" : ".");
256 if (!in_contents)
257 in_contents = g_strdup ("");
259 find_dlg =
260 create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
261 find_parm_callback, "[Find File]", _("Find File"),
262 DLG_CENTER | DLG_REVERSE);
264 add_widget (find_dlg,
265 button_new (12, b2, B_CANCEL, NORMAL_BUTTON, buts[2], 0));
266 add_widget (find_dlg,
267 button_new (12, b1, B_TREE, NORMAL_BUTTON, buts[1], 0));
268 add_widget (find_dlg,
269 button_new (12, b0, B_ENTER, DEFPUSH_BUTTON, buts[0], 0));
271 recursively_cbox =
272 check_new (6, istart, find_recursively, recurs_label);
274 find_regex_cbox = check_new (10, istart, find_regex_flag, _("&Regular expression"));
275 add_widget (find_dlg, find_regex_cbox);
277 case_sense = check_new (9, istart, case_sensitive, case_label);
278 add_widget (find_dlg, case_sense);
280 in_with =
281 input_new (8, istart, INPUT_COLOR, ilen, in_contents, "content", INPUT_COMPLETE_DEFAULT);
282 add_widget (find_dlg, in_with);
284 add_widget (find_dlg, recursively_cbox);
285 in_name =
286 input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name", INPUT_COMPLETE_DEFAULT);
287 add_widget (find_dlg, in_name);
289 in_start =
290 input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
291 add_widget (find_dlg, in_start);
293 add_widget (find_dlg, label_new (8, 3, labs[2]));
294 add_widget (find_dlg, label_new (5, 3, labs[1]));
295 add_widget (find_dlg, label_new (3, 3, labs[0]));
297 dlg_select_widget (in_name);
299 run_dlg (find_dlg);
301 switch (find_dlg->ret_value) {
302 case B_CANCEL:
303 return_value = 0;
304 break;
306 case B_TREE:
307 temp_dir = g_strdup (in_start->buffer);
308 case_sensitive = case_sense->state & C_BOOL;
309 find_regex_flag = find_regex_cbox->state & C_BOOL;
310 find_recursively = recursively_cbox->state & C_BOOL;
311 destroy_dlg (find_dlg);
312 g_free (in_start_dir);
313 if (strcmp (temp_dir, ".") == 0) {
314 g_free (temp_dir);
315 temp_dir = g_strdup (current_panel->cwd);
317 in_start_dir = tree_box (temp_dir);
318 if (in_start_dir)
319 g_free (temp_dir);
320 else
321 in_start_dir = temp_dir;
322 /* Warning: Dreadful goto */
323 goto find_par_start;
324 break;
326 default:
327 g_free (in_contents);
328 if (in_with->buffer[0]) {
329 *content = g_strdup (in_with->buffer);
330 in_contents = g_strdup (*content);
331 } else {
332 *content = in_contents = NULL;
333 r = 0;
336 case_sensitive = case_sense->state & C_BOOL;
337 find_regex_flag = find_regex_cbox->state & C_BOOL;
338 find_recursively = recursively_cbox->state & C_BOOL;
339 return_value = 1;
340 *start_dir = g_strdup (in_start->buffer);
341 *pattern = g_strdup (in_name->buffer);
343 g_free (in_start_dir);
344 in_start_dir = g_strdup (*start_dir);
345 g_free (in_start_name);
346 in_start_name = g_strdup (*pattern);
349 destroy_dlg (find_dlg);
351 return return_value;
354 static void
355 push_directory (const char *dir)
357 dir_stack *new;
359 new = g_new (dir_stack, 1);
360 new->name = mhl_str_dir_plus_file (dir, NULL);
361 new->prev = dir_stack_base;
362 dir_stack_base = new;
365 static char*
366 pop_directory (void)
368 char *name;
369 dir_stack *next;
371 if (dir_stack_base){
372 name = dir_stack_base->name;
373 next = dir_stack_base->prev;
374 g_free (dir_stack_base);
375 dir_stack_base = next;
376 return name;
377 } else
378 return 0;
381 static void
382 insert_file (const char *dir, const char *file)
384 char *tmp_name;
385 static char *dirname;
387 while (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
388 dir++;
390 if (old_dir){
391 if (strcmp (old_dir, dir)){
392 g_free (old_dir);
393 old_dir = g_strdup (dir);
394 dirname = add_to_list (dir, NULL);
396 } else {
397 old_dir = g_strdup (dir);
398 dirname = add_to_list (dir, NULL);
401 tmp_name = g_strconcat (" ", file, (char *) NULL);
402 add_to_list (tmp_name, dirname);
403 g_free (tmp_name);
406 static void
407 find_add_match (Dlg_head *h, const char *dir, const char *file)
409 int p = ++matches & 7;
411 (void) h;
413 insert_file (dir, file);
415 /* Scroll nicely */
416 if (!p)
417 listbox_select_last (find_list, 1);
418 else
419 listbox_select_last (find_list, 0);
420 /* Updates the current listing */
421 send_message (&find_list->widget, WIDGET_DRAW, 0);
422 if (p == 7)
423 mc_refresh ();
427 * get_line_at:
429 * Returns malloced null-terminated line from file file_fd.
430 * Input is buffered in buf_size long buffer.
431 * Current pos in buf is stored in pos.
432 * n_read - number of read chars.
433 * has_newline - is there newline ?
435 static char *
436 get_line_at (int file_fd, char *buf, int *pos, int *n_read, int buf_size,
437 int *has_newline)
439 char *buffer = 0;
440 int buffer_size = 0;
441 char ch = 0;
442 int i = 0;
444 for (;;) {
445 if (*pos >= *n_read) {
446 *pos = 0;
447 if ((*n_read = mc_read (file_fd, buf, buf_size)) <= 0)
448 break;
451 ch = buf[(*pos)++];
452 if (ch == 0) {
453 /* skip possible leading zero(s) */
454 if (i == 0)
455 continue;
456 else
457 break;
460 if (i >= buffer_size - 1) {
461 buffer = g_realloc (buffer, buffer_size += 80);
463 /* Strip newline */
464 if (ch == '\n')
465 break;
467 buffer[i++] = ch;
470 *has_newline = ch ? 1 : 0;
472 if (buffer) {
473 buffer[i] = 0;
476 return buffer;
479 static FindProgressStatus
480 check_find_events(Dlg_head *h)
482 Gpm_Event event;
483 int c;
485 c = get_event (&event, h->mouse_status == MOU_REPEAT, 0);
486 if (c != EV_NONE) {
487 dlg_process_event (h, c, &event);
488 if (h->ret_value == B_ENTER
489 || h->ret_value == B_CANCEL
490 || h->ret_value == B_AGAIN
491 || h->ret_value == B_PANELIZE) {
492 /* dialog terminated */
493 return FIND_ABORT;
495 if (!(h->flags & DLG_WANT_IDLE)) {
496 /* searching suspended */
497 return FIND_SUSPEND;
501 return FIND_CONT;
505 * search_content:
507 * Search the global (FIXME) regexp compiled content_pattern string in the
508 * DIRECTORY/FILE. It will add the found entries to the find listbox.
510 * returns 0 if do_search should look for another file
511 * 1 if do_search should exit and proceed to the event handler
513 static int
514 search_content (Dlg_head *h, const char *directory, const char *filename)
516 struct stat s;
517 char buffer [BUF_SMALL];
518 char *fname;
519 int file_fd;
520 int ret_val = 0;
522 fname = mhl_str_dir_plus_file (directory, filename);
524 if (mc_stat (fname, &s) != 0 || !S_ISREG (s.st_mode)){
525 g_free (fname);
526 return 0;
529 file_fd = mc_open (fname, O_RDONLY);
530 g_free (fname);
532 if (file_fd == -1)
533 return 0;
535 g_snprintf (buffer, sizeof (buffer), _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
537 status_update (buffer);
538 mc_refresh ();
540 enable_interrupt_key ();
541 got_interrupt ();
544 int line = 1;
545 int pos = 0;
546 int n_read = 0;
547 int has_newline;
548 char *p;
549 int found = 0;
550 typedef const char * (*search_fn) (const char *, const char *);
551 search_fn search_func;
553 if (resuming) {
554 /* We've been previously suspended, start from the previous position */
555 resuming = 0;
556 line = last_line;
557 pos = last_pos;
560 search_func = (case_sensitive) ? cstrstr : cstrcasestr;
562 while ((p = get_line_at (file_fd, buffer, &pos, &n_read, sizeof (buffer), &has_newline)) && (ret_val == 0)){
563 if (found == 0){ /* Search in binary line once */
564 if (find_regex_flag) {
565 if (regexec (r, p, 1, 0, 0) == 0){
566 g_free (p);
567 p = g_strdup_printf ("%d:%s", line, filename);
568 find_add_match (h, directory, p);
569 found = 1;
571 } else {
572 if (search_func (p, content_pattern) != NULL) {
573 char *match = g_strdup_printf("%d:%s", line, filename);
574 find_add_match (h, directory, match);
575 found = TRUE;
579 if (has_newline){
580 line++;
581 found = 0;
583 g_free (p);
585 if ((line & 0xff) == 0) {
586 FindProgressStatus res;
587 res = check_find_events(h);
588 switch (res) {
589 case FIND_ABORT:
590 stop_idle (h);
591 ret_val = 1;
592 break;
593 case FIND_SUSPEND:
594 resuming = 1;
595 last_line = line;
596 last_pos = pos;
597 ret_val = 1;
598 break;
599 default:
600 break;
606 disable_interrupt_key ();
607 mc_close (file_fd);
608 return ret_val;
611 static int
612 do_search (struct Dlg_head *h)
614 static struct dirent *dp = 0;
615 static DIR *dirp = 0;
616 static char *directory;
617 struct stat tmp_stat;
618 static int pos;
619 static int subdirs_left = 0;
621 if (!h) { /* someone forces me to close dirp */
622 if (dirp) {
623 mc_closedir (dirp);
624 dirp = 0;
626 g_free (directory);
627 directory = NULL;
628 dp = 0;
629 return 1;
631 do_search_begin:
632 while (!dp){
634 if (dirp){
635 mc_closedir (dirp);
636 dirp = 0;
639 while (!dirp){
640 char *tmp;
642 attrset (REVERSE_COLOR);
643 while (1) {
644 tmp = pop_directory ();
645 if (!tmp){
646 running = 0;
647 status_update (_("Finished"));
648 stop_idle (h);
649 return 0;
651 if (find_ignore_dirs){
652 int found;
653 char *temp_dir = g_strconcat (":", tmp, ":", (char *) NULL);
655 found = strstr (find_ignore_dirs, temp_dir) != 0;
656 g_free (temp_dir);
657 if (found)
658 g_free (tmp);
659 else
660 break;
661 } else
662 break;
665 g_free (directory);
666 directory = tmp;
668 if (verbose){
669 char buffer [BUF_SMALL];
671 g_snprintf (buffer, sizeof (buffer), _("Searching %s"),
672 name_trunc (directory, FIND2_X_USE));
673 status_update (buffer);
675 /* mc_stat should not be called after mc_opendir
676 because vfs_s_opendir modifies the st_nlink
678 if (!mc_stat (directory, &tmp_stat))
679 subdirs_left = tmp_stat.st_nlink - 2;
680 else
681 subdirs_left = 0;
682 /* Commented out as unnecessary
683 if (subdirs_left < 0)
684 subdirs_left = MAXINT;
686 dirp = mc_opendir (directory);
687 } /* while (!dirp) */
688 dp = mc_readdir (dirp);
689 } /* while (!dp) */
691 if (strcmp (dp->d_name, ".") == 0 ||
692 strcmp (dp->d_name, "..") == 0){
693 dp = mc_readdir (dirp);
694 return 1;
697 if (subdirs_left && find_recursively && directory) { /* Can directory be NULL ? */
698 char *tmp_name = mhl_str_dir_plus_file (directory, dp->d_name);
699 if (!mc_lstat (tmp_name, &tmp_stat)
700 && S_ISDIR (tmp_stat.st_mode)) {
701 push_directory (tmp_name);
702 subdirs_left--;
704 g_free (tmp_name);
707 if (regexp_match (find_pattern, dp->d_name, match_file)){
708 if (content_pattern) {
709 if (search_content (h, directory, dp->d_name)) {
710 return 1;
712 } else
713 find_add_match (h, directory, dp->d_name);
716 dp = mc_readdir (dirp);
718 /* Displays the nice dot */
719 count++;
720 if (!(count & 31)){
721 /* For nice updating */
722 const char *rotating_dash = "|/-\\";
724 if (verbose){
725 pos = (pos + 1) % 4;
726 attrset (DLG_NORMALC (h));
727 dlg_move (h, FIND2_Y-6, FIND2_X - 4);
728 addch (rotating_dash [pos]);
729 mc_refresh ();
731 } else
732 goto do_search_begin;
733 return 1;
736 static void
737 init_find_vars (void)
739 char *dir;
741 g_free (old_dir);
742 old_dir = 0;
743 count = 0;
744 matches = 0;
746 /* Remove all the items in the stack */
747 while ((dir = pop_directory ()) != NULL)
748 g_free (dir);
751 static char *
752 make_fullname (const char *dirname, const char *filename)
755 if (strcmp(dirname, ".") == 0 || strcmp(dirname, "."PATH_SEP_STR) == 0)
756 return g_strdup (filename);
757 if (strncmp(dirname, "."PATH_SEP_STR, 2) == 0)
758 return mhl_str_dir_plus_file (dirname + 2, filename);
759 return mhl_str_dir_plus_file (dirname, filename);
762 static void
763 find_do_view_edit (int unparsed_view, int edit, char *dir, char *file)
765 char *fullname;
766 const char *filename;
767 int line;
769 if (content_pattern){
770 filename = strchr (file + 4, ':') + 1;
771 line = atoi (file + 4);
772 } else {
773 filename = file + 4;
774 line = 0;
777 fullname = make_fullname (dir, filename);
778 if (edit)
779 do_edit_at_line (fullname, line);
780 else
781 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
782 g_free (fullname);
785 static int
786 view_edit_currently_selected_file (int unparsed_view, int edit)
788 WLEntry *entry = find_list->current;
789 char *dir;
791 if (!entry)
792 return MSG_NOT_HANDLED;
794 dir = entry->data;
796 if (!entry->text || !dir)
797 return MSG_NOT_HANDLED;
799 find_do_view_edit (unparsed_view, edit, dir, entry->text);
800 return MSG_HANDLED;
803 static cb_ret_t
804 find_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
806 switch (msg) {
807 case DLG_KEY:
808 if (parm == KEY_F (3) || parm == KEY_F (13)) {
809 int unparsed_view = (parm == KEY_F (13));
810 return view_edit_currently_selected_file (unparsed_view, 0);
812 if (parm == KEY_F (4)) {
813 return view_edit_currently_selected_file (0, 1);
815 return MSG_NOT_HANDLED;
817 case DLG_IDLE:
818 do_search (h);
819 return MSG_HANDLED;
821 default:
822 return default_dlg_callback (h, msg, parm);
826 /* Handles the Stop/Start button in the find window */
827 static int
828 start_stop (int button)
830 (void) button;
832 running = is_start;
833 set_idle_proc (find_dlg, running);
834 is_start = !is_start;
836 status_update (is_start ? _("Stopped") : _("Searching"));
837 button_set_text (stop_button, fbuts [is_start].text);
839 return 0;
842 /* Handle view command, when invoked as a button */
843 static int
844 find_do_view_file (int button)
846 (void) button;
848 view_edit_currently_selected_file (0, 0);
849 return 0;
852 /* Handle edit command, when invoked as a button */
853 static int
854 find_do_edit_file (int button)
856 (void) button;
858 view_edit_currently_selected_file (0, 1);
859 return 0;
862 static void
863 setup_gui (void)
865 #ifdef ENABLE_NLS
866 static int i18n_flag = 0;
867 if (!i18n_flag) {
868 register int i = sizeof (fbuts) / sizeof (fbuts[0]);
869 while (i--)
870 fbuts[i].len = strlen (fbuts[i].text = _(fbuts[i].text)) + 3;
871 fbuts[2].len += 2; /* DEFPUSH_BUTTON */
872 i18n_flag = 1;
874 #endif /* ENABLE_NLS */
877 * Dynamically place buttons centered within current window size
880 int l0 = max (fbuts[0].len, fbuts[1].len);
881 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
882 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
883 int r1, r2;
885 FIND2_X = COLS - 16;
887 /* Check, if both button rows fit within FIND2_X */
888 if (l1 + 9 > FIND2_X)
889 FIND2_X = l1 + 9;
890 if (l2 + 8 > FIND2_X)
891 FIND2_X = l2 + 8;
893 /* compute amount of space between buttons for each row */
894 r1 = (FIND2_X - 4 - l1) % 5;
895 l1 = (FIND2_X - 4 - l1) / 5;
896 r2 = (FIND2_X - 4 - l2) % 4;
897 l2 = (FIND2_X - 4 - l2) / 4;
899 /* ...and finally, place buttons */
900 fbuts[2].x = 2 + r1 / 2 + l1;
901 fbuts[3].x = fbuts[2].x + fbuts[2].len + l1;
902 fbuts[0].x = fbuts[3].x + fbuts[3].len + l1;
903 fbuts[4].x = fbuts[0].x + l0 + l1;
904 fbuts[5].x = 2 + r2 / 2 + l2;
905 fbuts[6].x = fbuts[5].x + fbuts[5].len + l2;
906 fbuts[7].x = fbuts[6].x + fbuts[6].len + l2;
909 find_dlg =
910 create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors, find_callback,
911 "[Find File]", _("Find File"), DLG_CENTER | DLG_REVERSE);
913 add_widget (find_dlg,
914 button_new (FIND2_Y - 3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
915 fbuts[7].text, find_do_edit_file));
916 add_widget (find_dlg,
917 button_new (FIND2_Y - 3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
918 fbuts[6].text, find_do_view_file));
919 add_widget (find_dlg,
920 button_new (FIND2_Y - 3, fbuts[5].x, B_PANELIZE,
921 NORMAL_BUTTON, fbuts[5].text, 0));
923 add_widget (find_dlg,
924 button_new (FIND2_Y - 4, fbuts[4].x, B_CANCEL,
925 NORMAL_BUTTON, fbuts[4].text, 0));
926 stop_button =
927 button_new (FIND2_Y - 4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
928 fbuts[0].text, start_stop);
929 add_widget (find_dlg, stop_button);
930 add_widget (find_dlg,
931 button_new (FIND2_Y - 4, fbuts[3].x, B_AGAIN,
932 NORMAL_BUTTON, fbuts[3].text, 0));
933 add_widget (find_dlg,
934 button_new (FIND2_Y - 4, fbuts[2].x, B_ENTER,
935 DEFPUSH_BUTTON, fbuts[2].text, 0));
937 status_label = label_new (FIND2_Y - 6, 4, _("Searching"));
938 add_widget (find_dlg, status_label);
940 find_list =
941 listbox_new (2, 2, FIND2_X - 4, FIND2_Y - 9, 0);
942 add_widget (find_dlg, find_list);
945 static int
946 run_process (void)
948 resuming = 0;
949 set_idle_proc (find_dlg, 1);
950 run_dlg (find_dlg);
951 return find_dlg->ret_value;
954 static void
955 kill_gui (void)
957 set_idle_proc (find_dlg, 0);
958 destroy_dlg (find_dlg);
961 static int
962 find_file (char *start_dir, char *pattern, char *content, char **dirname,
963 char **filename)
965 int return_value = 0;
966 char *dir;
967 char *dir_tmp, *file_tmp;
969 setup_gui ();
971 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
972 find_pattern = pattern;
973 content_pattern = content;
975 init_find_vars ();
976 push_directory (start_dir);
978 return_value = run_process ();
980 /* Remove all the items in the stack */
981 while ((dir = pop_directory ()) != NULL)
982 g_free (dir);
984 get_list_info (&file_tmp, &dir_tmp);
986 if (dir_tmp)
987 *dirname = g_strdup (dir_tmp);
988 if (file_tmp)
989 *filename = g_strdup (file_tmp);
991 if (return_value == B_PANELIZE && *filename) {
992 int status, link_to_dir, stale_link;
993 int next_free = 0;
994 int i;
995 struct stat st;
996 WLEntry *entry = find_list->list;
997 dir_list *list = &current_panel->dir;
998 char *name;
1000 for (i = 0; entry && i < find_list->count;
1001 entry = entry->next, i++) {
1002 const char *filename;
1004 if (!entry->text || !entry->data)
1005 continue;
1007 if (content_pattern)
1008 filename = strchr (entry->text + 4, ':') + 1;
1009 else
1010 filename = entry->text + 4;
1012 name = make_fullname (entry->data, filename);
1013 status =
1014 handle_path (list, name, &st, next_free, &link_to_dir,
1015 &stale_link);
1016 if (status == 0) {
1017 g_free (name);
1018 continue;
1020 if (status == -1) {
1021 g_free (name);
1022 break;
1025 /* don't add files more than once to the panel */
1026 if (content_pattern && next_free > 0) {
1027 if (strcmp (list->list[next_free - 1].fname, name) == 0) {
1028 g_free (name);
1029 continue;
1033 if (!next_free) /* first turn i.e clean old list */
1034 panel_clean_dir (current_panel);
1035 list->list[next_free].fnamelen = strlen (name);
1036 list->list[next_free].fname = name;
1037 list->list[next_free].f.marked = 0;
1038 list->list[next_free].f.link_to_dir = link_to_dir;
1039 list->list[next_free].f.stale_link = stale_link;
1040 list->list[next_free].f.dir_size_computed = 0;
1041 list->list[next_free].st = st;
1042 next_free++;
1043 if (!(next_free & 15))
1044 rotate_dash ();
1046 if (next_free) {
1047 current_panel->count = next_free;
1048 current_panel->is_panelized = 1;
1049 /* Done by panel_clean_dir a few lines above
1050 current_panel->dirs_marked = 0;
1051 current_panel->marked = 0;
1052 current_panel->total = 0;
1053 current_panel->top_file = 0;
1054 current_panel->selected = 0; */
1056 if (start_dir[0] == PATH_SEP) {
1057 strcpy (current_panel->cwd, PATH_SEP_STR);
1058 chdir (PATH_SEP_STR);
1063 kill_gui ();
1064 do_search (0); /* force do_search to release resources */
1065 g_free (old_dir);
1066 old_dir = 0;
1068 return return_value;
1071 void
1072 do_find (void)
1074 char *start_dir = NULL, *pattern = NULL, *content = NULL;
1075 char *filename, *dirname;
1076 int v, dir_and_file_set;
1077 regex_t rx; /* Compiled content_pattern to search inside files */
1079 for (r = &rx; find_parameters (&start_dir, &pattern, &content); r = &rx){
1081 dirname = filename = NULL;
1082 is_start = 0;
1083 v = find_file (start_dir, pattern, content, &dirname, &filename);
1084 g_free (start_dir);
1085 g_free (pattern);
1086 if (find_regex_flag && r)
1087 regfree (r);
1089 if (v == B_ENTER){
1090 if (dirname || filename){
1091 if (dirname){
1092 do_cd (dirname, cd_exact);
1093 if (filename)
1094 try_to_select (current_panel, filename + (content ?
1095 (strchr (filename + 4, ':') - filename + 1) : 4) );
1096 } else if (filename)
1097 do_cd (filename, cd_exact);
1098 select_item (current_panel);
1100 g_free (dirname);
1101 g_free (filename);
1102 break;
1104 g_free (content);
1105 dir_and_file_set = dirname && filename;
1106 g_free (dirname);
1107 g_free (filename);
1108 if (v == B_CANCEL)
1109 break;
1111 if (v == B_PANELIZE){
1112 if (dir_and_file_set){
1113 try_to_select (current_panel, NULL);
1114 panel_re_sort (current_panel);
1115 try_to_select (current_panel, NULL);
1117 break;