- Rearrange reactos.dff according to rosapps rearrange.
[reactos.git] / rosapps / applications / mc / src / find.c
1 /* Find file command for the Midnight Commander
2 Copyright (C) The Free Software Foundation
3 Written 1995 by Miguel de Icaza
4
5 Complete rewrote.
6
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.
11
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.
16
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include <config.h>
22 #include "tty.h"
23 #include <string.h>
24 #include <stdio.h>
25 #ifdef OS2_NT
26 # include <io.h>
27 #endif
28 #include "fs.h"
29 #include <malloc.h> /* For free() */
30 #include <sys/stat.h>
31 #include <sys/param.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <ctype.h>
35 #include "global.h"
36 #include "mad.h"
37 #include "util.h"
38 #include "win.h"
39 #include "color.h"
40 #include "global.h"
41
42 extern int verbose; /* Should be in a more sensible header file */
43
44 /* Dialog manager and widgets */
45 #include "dlg.h"
46 #include "widget.h"
47
48 #include "dialog.h" /* For do_refresh() */
49 #define DIR_H_INCLUDE_HANDLE_DIRENT
50 #include "dir.h"
51 #include "panel.h" /* current_panel */
52 #include "main.h" /* do_cd, try_to_select */
53 #include "wtools.h"
54 #include "tree.h"
55 #include "cmd.h" /* view_file_at_line */
56 #include "../vfs/vfs.h"
57
58 #ifdef HAVE_XVIEW
59 #include "xvmain.h"
60 #endif
61
62 #ifndef PORT_HAS_FLUSH_EVENTS
63 # define x_flush_events()
64 #endif
65
66 /* Size of the find parameters window */
67 #define FIND_Y 12
68 static int FIND_X = 50;
69
70 /* Size of the find window */
71 #define FIND2_Y LINES-4
72 static int FIND2_X = 64;
73
74 #ifdef HAVE_X
75 # define FIND2_X_USE 35
76 #else
77 # define FIND2_X_USE FIND2_X-20
78 #endif
79
80 /* A couple of extra messages we need */
81 enum {
82 B_STOP = B_USER + 1,
83 B_AGAIN,
84 B_PANELIZE,
85 B_TREE,
86 B_VIEW
87 };
88
89 /* A list of directories to be ignores, separated with ':' */
90 char *find_ignore_dirs = 0;
91
92 static Dlg_head *find_dlg; /* The dialog */
93 static WInput *in_start; /* Start path */
94 static WInput *in_name; /* Pattern to search */
95 static WInput *in_with; /* text inside filename */
96 static WListbox *find_list; /* Listbox with the file list */
97 static int running = 0; /* nice flag */
98 static WButton *stop_button; /* pointer to the stop button */
99 static WLabel *status_label; /* Finished, Searching etc. */
100 static char *find_pattern; /* Pattern to search */
101 static char *content_pattern; /* pattern to search inside files */
102 static int count; /* Number of files displayed */
103 static int matches; /* Number of matches */
104 static int is_start; /* Status of the start/stop toggle button */
105 int max_loops_in_idle = 10;
106 static char *old_dir;
107
108 /* For nice updating */
109 static char *rotating_dash = "|/-\\";
110
111 /* This keeps track of the directory stack */
112 typedef struct dir_stack {
113 char *name;
114 struct dir_stack *prev;
115 } dir_stack ;
116
117 dir_stack *dir_stack_base = 0;
118
119 static struct {
120 char* text;
121 int len; /* length including space and brackets */
122 int x;
123 } fbuts [] = {
124 { N_("&Suspend"), 11, 29 },
125 { N_("Con&tinue"), 12, 29 },
126 { N_("&Chdir"), 11, 3 },
127 { N_("&Again"), 9, 17 },
128 { N_("&Quit"), 8, 43 },
129 { N_("Pane&lize"), 12, 3 },
130 { N_("&View - F3"), 13, 20 },
131 { N_("&Edit - F4"), 13, 38 }
132 };
133
134 /*
135 * find_parameters: gets information from the user
136 *
137 * If the return value is true, then the following holds:
138 *
139 * START_DIR and PATTERN are pointers to char * and upon return they
140 * contain the information provided by the user.
141 *
142 * CONTENT holds a strdup of the contents specified by the user if he
143 * asked for them or 0 if not (note, this is different from the
144 * behavior for the other two parameters.
145 *
146 */
147
148 static int
149 find_parameters (char **start_dir, char **pattern, char **content)
150 {
151 int return_value;
152 char *temp_dir;
153 static char *in_contents = NULL;
154 static char *in_start_dir = NULL;
155 static char *in_start_name = NULL;
156
157 static char* labs[] = {N_("Start at:"), N_("Filename:"), N_("Content: ")};
158 static char* buts[] = {N_("&Ok"), N_("&Tree"), N_("&Cancel")};
159 static int ilen = 30, istart = 14;
160 static int b0 = 3, b1 = 16, b2 = 36;
161
162 #ifdef ENABLE_NLS
163 static int i18n_flag = 0;
164
165 if (!i18n_flag)
166 {
167 register int i = sizeof(labs)/sizeof(labs[0]);
168 int l1, maxlen = 0;
169
170 while (i--)
171 {
172 l1 = strlen (labs [i] = _(labs [i]));
173 if (l1 > maxlen)
174 maxlen = l1;
175 }
176 i = maxlen + ilen + 7;
177 if (i > FIND_X)
178 FIND_X = i;
179
180 for (i = sizeof(buts)/sizeof(buts[0]), l1 = 0; i--; )
181 {
182 l1 += strlen (buts [i] = _(buts [i]));
183 }
184 l1 += 21;
185 if (l1 > FIND_X)
186 FIND_X = l1;
187
188 ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
189 istart = FIND_X - 3 - ilen;
190
191 b1 = b0 + strlen(buts[0]) + 7;
192 b2 = FIND_X - (strlen(buts[2]) + 6);
193
194 i18n_flag = 1;
195 }
196
197 #endif /* ENABLE_NLS */
198
199 find_par_start:
200 if (!in_start_dir)
201 in_start_dir = strdup (".");
202 if (!in_start_name)
203 in_start_name = strdup (easy_patterns ? "*" : ".");
204 if (!in_contents)
205 in_contents = strdup ("");
206
207 find_dlg = create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
208 common_dialog_callback, "[Find File]", "findfile",
209 DLG_CENTER | DLG_GRID);
210 x_set_dialog_title (find_dlg, _("Find File"));
211
212 add_widgetl (find_dlg, button_new (9, b2, B_CANCEL, NORMAL_BUTTON,
213 buts[2], 0 ,0, "cancel"), XV_WLAY_RIGHTOF);
214 #ifndef HAVE_GNOME
215 add_widgetl (find_dlg, button_new (9, b1, B_TREE, NORMAL_BUTTON,
216 buts[1], 0, 0, "tree"), XV_WLAY_RIGHTOF);
217 #endif
218 add_widgetl (find_dlg, button_new (9, b0, B_ENTER, DEFPUSH_BUTTON,
219 buts[0], 0, 0, "ok"), XV_WLAY_CENTERROW);
220
221 in_with = input_new (7, istart, INPUT_COLOR, ilen, in_contents, "content");
222 add_widgetl (find_dlg, in_with, XV_WLAY_BELOWOF);
223
224 in_name = input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name");
225 add_widgetl (find_dlg, in_name, XV_WLAY_BELOWOF);
226
227 in_start = input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start");
228 add_widgetl (find_dlg, in_start, XV_WLAY_NEXTCOLUMN);
229
230 add_widgetl (find_dlg, label_new (7, 3, labs[2], "label-cont"), XV_WLAY_BELOWOF);
231 add_widgetl (find_dlg, label_new (5, 3, labs[1], "label-file"), XV_WLAY_BELOWOF);
232 add_widgetl (find_dlg, label_new (3, 3, labs[0], "label-start"), XV_WLAY_NEXTCOLUMN);
233
234 run_dlg (find_dlg);
235 if (find_dlg->ret_value == B_CANCEL)
236 return_value = 0;
237 else if (find_dlg->ret_value == B_TREE){
238 temp_dir = strdup (in_start->buffer);
239 destroy_dlg (find_dlg);
240 free (in_start_dir);
241 if (strcmp (temp_dir, ".") == 0){
242 free (temp_dir);
243 temp_dir = strdup (cpanel->cwd);
244 }
245 in_start_dir = tree (temp_dir);
246 if (in_start_dir)
247 free (temp_dir);
248 else
249 in_start_dir = temp_dir;
250 /* Warning: Dreadful goto */
251 goto find_par_start;
252 } else {
253 return_value = 1;
254 *start_dir = strdup (in_start->buffer);
255 *pattern = strdup (in_name->buffer);
256
257 free (in_contents);
258 if (in_with->buffer [0]){
259 *content = strdup (in_with->buffer);
260 in_contents = strdup (*content);
261 } else
262 *content = in_contents = NULL;
263
264 free (in_start_dir);
265 in_start_dir = strdup (*start_dir);
266 free (in_start_name);
267 in_start_name = strdup (*pattern);
268 }
269
270 destroy_dlg (find_dlg);
271
272 return return_value;
273 }
274
275 static void
276 push_directory (char *dir)
277 {
278 dir_stack *new;
279
280 new = xmalloc (sizeof (dir_stack), "find: push_directory");
281 new->name = strdup (dir);
282 new->prev = dir_stack_base;
283 dir_stack_base = new;
284 }
285
286 static char*
287 pop_directory (void)
288 {
289 char *name;
290 dir_stack *next;
291
292 if (dir_stack_base){
293 name = dir_stack_base->name;
294 next = dir_stack_base->prev;
295 free (dir_stack_base);
296 dir_stack_base = next;
297 return name;
298 } else
299 return 0;
300 }
301
302 static void
303 insert_file (char *dir, char *file)
304 {
305 char *tmp_name;
306 static char *dirname;
307 int i;
308
309 if (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
310 dir++;
311 i = strlen (dir);
312 if (i){
313 if (dir [i - 1] != PATH_SEP){
314 dir [i] = PATH_SEP;
315 dir [i + 1] = 0;
316 }
317 }
318
319 if (old_dir){
320 if (strcmp (old_dir, dir)){
321 free (old_dir);
322 old_dir = strdup (dir);
323 dirname = listbox_add_item (find_list, 0, 0, dir, 0);
324 }
325 } else {
326 old_dir = strdup (dir);
327 dirname = listbox_add_item (find_list, 0, 0, dir, 0);
328 }
329
330 tmp_name = copy_strings (" ", file, 0);
331 listbox_add_item (find_list, 0, 0, tmp_name, dirname);
332 free (tmp_name);
333 }
334
335 static void
336 find_add_match (Dlg_head *h, char *dir, char *file)
337 {
338 int p = ++matches & 7;
339
340 insert_file (dir, file);
341
342 /* Scroll nicely */
343 if (!p)
344 listbox_select_last (find_list, 1);
345 else
346 listbox_select_last (find_list, 0);
347
348 #ifndef HAVE_X
349 /* Updates the current listing */
350 send_message (h, &find_list->widget, WIDGET_DRAW, 0);
351 if (p == 7)
352 mc_refresh ();
353 #endif
354 }
355
356 char *
357 locate_egrep (void)
358 {
359 char *paths [] = {
360 "/bin/egrep",
361 "/usr/bin/egrep",
362 "/sbin/egrep",
363 "/usr/sbin/egrep",
364 NULL
365 };
366 struct stat s;
367 char **p;
368
369 for (p = &paths [0]; *p; p++){
370 if (stat (*p, &s) == 0)
371 return *p;
372 }
373 return "egrep";
374 }
375
376 /*
377 * search_content:
378 *
379 * Search with egrep the global (FIXME) content_pattern string in the
380 * DIRECTORY/FILE. It will add the found entries to the find listbox.
381 */
382 void
383 search_content (Dlg_head *h, char *directory, char *filename)
384 {
385 struct stat s;
386 char buffer [128];
387 char *fname, *p;
388 int file_fd, pipe, ignoring;
389 char c;
390 int i;
391 pid_t pid;
392 static char *egrep_path;
393
394 fname = get_full_name (directory, filename);
395
396 if (mc_stat (fname, &s) != 0 && !S_ISREG (s.st_mode)){
397 free (fname);
398 return;
399 }
400 if (!S_ISREG (s.st_mode)){
401 free (fname);
402 return;
403 }
404
405 file_fd = mc_open (fname, O_RDONLY);
406 free (fname);
407
408 if (file_fd == -1)
409 return;
410
411 if (!egrep_path)
412 egrep_path = locate_egrep ();
413
414 #ifndef GREP_STDIN
415 pipe = mc_doublepopen (file_fd, -1, &pid, egrep_path, egrep_path, "-n", content_pattern, NULL);
416 #else /* GREP_STDIN */
417 pipe = mc_doublepopen (file_fd, -1, &pid, egrep_path, egrep_path, "-n", content_pattern, "-", NULL);
418 #endif /* GREP STDIN */
419
420 if (pipe == -1){
421 mc_close (file_fd);
422 return;
423 }
424
425 sprintf (buffer, _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
426
427 label_set_text (status_label, buffer);
428 mc_refresh ();
429 p = buffer;
430 ignoring = 0;
431
432 enable_interrupt_key ();
433 got_interrupt ();
434 while (1){
435 i = read (pipe, &c, 1);
436 if (i != 1)
437 break;
438
439 if (c == '\n'){
440 p = buffer;
441 ignoring = 0;
442 }
443 if (ignoring)
444 continue;
445
446 if (c == ':'){
447 char *the_name;
448
449 *p = 0;
450 ignoring = 1;
451 the_name = copy_strings (buffer, ":", filename, NULL);
452 find_add_match (h, directory, the_name);
453 free (the_name);
454 } else {
455 if (p - buffer < (sizeof (buffer)-1) && ISASCII (c) && isdigit (c))
456 *p++ = c;
457 else
458 *p = 0;
459 }
460 }
461 disable_interrupt_key ();
462 if (i == -1)
463 message (1, _(" Find/read "), _(" Problem reading from child "));
464
465 mc_doublepclose (pipe, pid);
466 mc_close (file_fd);
467 }
468
469 static void
470 do_search (struct Dlg_head *h)
471 {
472 static struct dirent *dp = 0;
473 static DIR *dirp = 0;
474 static char directory [MC_MAXPATHLEN+2];
475 struct stat tmp_stat;
476 static int pos;
477 static int subdirs_left = 0;
478 char *tmp_name; /* For bulding file names */
479
480 if (!h) { /* someone forces me to close dirp */
481 if (dirp) {
482 mc_closedir (dirp);
483 dirp = 0;
484 }
485 dp = 0;
486 return;
487 }
488
489 do_search_begin:
490 while (!dp){
491
492 if (dirp){
493 mc_closedir (dirp);
494 dirp = 0;
495 }
496
497 while (!dirp){
498 char *tmp;
499
500 #ifndef HAVE_X
501 attrset (REVERSE_COLOR);
502 #endif
503 while (1) {
504 tmp = pop_directory ();
505 if (!tmp){
506 running = 0;
507 label_set_text (status_label, _("Finished"));
508 set_idle_proc (h, 0);
509 return;
510 }
511 if (find_ignore_dirs){
512 char *temp_dir = copy_strings (":", tmp, ":", 0);
513 if (strstr (find_ignore_dirs, temp_dir))
514 free (tmp);
515 else
516 break;
517 } else
518 break;
519 }
520
521 strcpy (directory, tmp);
522 free (tmp);
523
524 if (verbose){
525 char buffer [50];
526
527 sprintf (buffer, _("Searching %s"), name_trunc (directory, FIND2_X_USE));
528 label_set_text (status_label, buffer);
529 }
530 dirp = mc_opendir (directory);
531 mc_stat (directory, &tmp_stat);
532 subdirs_left = tmp_stat.st_nlink - 2;
533 /* Commented out as unnecessary
534 if (subdirs_left < 0)
535 subdirs_left = MAXINT;
536 */
537 }
538 dp = mc_readdir (dirp);
539 }
540
541 if (strcmp (dp->d_name, ".") == 0 ||
542 strcmp (dp->d_name, "..") == 0){
543 dp = mc_readdir (dirp);
544 #ifdef HAVE_XVIEW
545 xv_post_proc (h, (void (*)(void *))do_search, (void *)h);
546 #endif
547 return;
548 }
549
550 tmp_name = get_full_name (directory, dp->d_name);
551
552 if (subdirs_left){
553 mc_lstat (tmp_name, &tmp_stat);
554 if (S_ISDIR (tmp_stat.st_mode)){
555 push_directory (tmp_name);
556 subdirs_left--;
557 }
558 }
559
560 if (regexp_match (find_pattern, dp->d_name, match_file)){
561 if (content_pattern)
562 search_content (h, directory, dp->d_name);
563 else
564 find_add_match (h, directory, dp->d_name);
565 }
566
567 free (tmp_name);
568 dp = mc_readdir (dirp);
569
570 /* Displays the nice dot */
571 count++;
572 if (!(count & 31)){
573 if (verbose){
574 #ifndef HAVE_X
575 pos = (pos + 1) % 4;
576 attrset (NORMALC);
577 dlg_move (h, FIND2_Y-6, FIND2_X - 4);
578 addch (rotating_dash [pos]);
579 mc_refresh ();
580 }
581 } else
582 goto do_search_begin;
583 #else
584 }
585 }
586 #ifdef HAVE_XVIEW
587 xv_post_proc (h, (void (*)(void *))do_search, (void *)h);
588 #endif
589 #endif
590 x_flush_events ();
591 }
592
593 static int
594 view_edit_currently_selected_file (int unparsed_view, int edit)
595 {
596 WLEntry *entry = find_list->current;
597 char *dir, *fullname, *filename;
598 int line;
599
600 if (!entry)
601 return MSG_NOT_HANDLED;
602
603 dir = entry->data;
604
605 if (!entry->text || !dir)
606 return MSG_NOT_HANDLED;
607
608 if (content_pattern){
609 filename = strchr (entry->text + 4, ':') + 1;
610 line = atoi (entry->text + 4);
611 } else {
612 filename = entry->text + 4;
613 line = 0;
614 }
615 if (dir [0] == '.' && dir [1] == 0)
616 fullname = strdup (filename);
617 else if (dir [0] == '.' && dir [1] == PATH_SEP)
618 fullname = get_full_name (dir+2, filename);
619 else
620 fullname = get_full_name (dir, filename);
621
622 if (edit)
623 do_edit_at_line (fullname, line);
624 else
625 view_file_at_line (fullname, unparsed_view, use_internal_view, line);
626 free (fullname);
627 return MSG_HANDLED;
628 }
629
630 static int
631 find_callback (struct Dlg_head *h, int id, int Msg)
632 {
633 switch (Msg){
634 #ifndef HAVE_X
635 case DLG_DRAW:
636 common_dialog_repaint (h);
637 break;
638 #endif
639
640 case DLG_KEY:
641 if (id == KEY_F(3) || id == KEY_F(13)){
642 int unparsed_view = (id == KEY_F(13));
643 return view_edit_currently_selected_file (unparsed_view, 0);
644 }
645 if (id == KEY_F(4)){
646 return view_edit_currently_selected_file (0, 1);
647 }
648 return MSG_NOT_HANDLED;
649
650 case DLG_IDLE:
651 do_search (h);
652 break;
653 }
654 return 0;
655 }
656
657 /* Handles the Stop/Start button in the find window */
658 static int
659 start_stop (int button, void *extra)
660 {
661 running = is_start;
662 set_idle_proc (find_dlg, running);
663 is_start = !is_start;
664
665 label_set_text (status_label, is_start ? _("Stopped") : _("Searching"));
666 button_set_text (stop_button, fbuts [is_start].text);
667
668 return 0;
669 }
670
671 /* Handle view command, when invoked as a button */
672 static int
673 find_do_view_file (int button, void *extra)
674 {
675 view_edit_currently_selected_file (0, 0);
676 return 0;
677 }
678
679 /* Handle edit command, when invoked as a button */
680 static int
681 find_do_edit_file (int button, void *extra)
682 {
683 view_edit_currently_selected_file (0, 1);
684 return 0;
685 }
686
687 static void
688 init_find_vars (void)
689 {
690 char *dir;
691
692 if (old_dir){
693 free (old_dir);
694 old_dir = 0;
695 }
696 count = 0;
697 matches = 0;
698
699 /* Remove all the items in the stack */
700 while ((dir = pop_directory ()) != NULL)
701 free (dir);
702 }
703
704 static int
705 find_file (char *start_dir, char *pattern, char *content, char **dirname, char **filename)
706 {
707 int return_value = 0;
708 char *dir;
709 char *dir_tmp, *file_tmp;
710
711 #ifdef ENABLE_NLS
712 static int i18n_flag = 0;
713 if (!i18n_flag)
714 {
715 register int i = sizeof (fbuts) / sizeof (fbuts[0]);
716 while (i--)
717 fbuts [i].len = strlen (fbuts [i].text = _(fbuts [i].text)) + 3;
718 fbuts [2].len += 2; /* DEFPUSH_BUTTON */
719 i18n_flag = 1;
720 }
721 #endif /* ENABLE_NLS */
722
723 /*
724 * Dynamically place buttons centered within current window size
725 */
726 {
727 int l0 = max (fbuts[0].len, fbuts[1].len);
728 int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
729 int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
730 int r1, r2;
731
732 FIND2_X = COLS - 16;
733
734 /* Check, if both button rows fit within FIND2_X */
735 if (l1 + 9 > FIND2_X) FIND2_X = l1 + 9;
736 if (l2 + 8 > FIND2_X) FIND2_X = l2 + 8;
737
738 /* compute amount of space between buttons for each row */
739 r1 = (FIND2_X - 4 - l1) % 5;
740 l1 = (FIND2_X - 4 - l1) / 5;
741 r2 = (FIND2_X - 4 - l2) % 4;
742 l2 = (FIND2_X - 4 - l2) / 4;
743
744 /* ...and finally, place buttons */
745 fbuts [2].x = 2 + r1/2 + l1;
746 fbuts [3].x = fbuts [2].x + fbuts [2].len + l1;
747 fbuts [0].x = fbuts [3].x + fbuts [3].len + l1;
748 fbuts [4].x = fbuts [0].x + l0 + l1;
749 fbuts [5].x = 2 + r2/2 + l2;
750 fbuts [6].x = fbuts [5].x + fbuts [5].len + l2;
751 fbuts [7].x = fbuts [6].x + fbuts [6].len + l2;
752 }
753
754 find_dlg = create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors,
755 find_callback, "[Find File]", "mfind", DLG_CENTER | DLG_GRID);
756
757 x_set_dialog_title (find_dlg, _("Find file"));
758
759 add_widgetl (find_dlg,
760 button_new (FIND2_Y-3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
761 fbuts[7].text, find_do_edit_file, find_dlg, "button-edit"), 0);
762 add_widgetl (find_dlg,
763 button_new (FIND2_Y-3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
764 fbuts[6].text, find_do_view_file, find_dlg, "button-view"), 0);
765 add_widgetl (find_dlg,
766 button_new (FIND2_Y-3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON,
767 fbuts[5].text, 0, 0, "button-panelize"), XV_WLAY_CENTERROW);
768
769 add_widgetl (find_dlg,
770 button_new (FIND2_Y-4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON,
771 fbuts[4].text, 0, 0, "button-quit"), XV_WLAY_RIGHTOF);
772 stop_button = button_new (FIND2_Y-4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
773 fbuts[0].text, start_stop, find_dlg, "start-stop");
774 add_widgetl (find_dlg, stop_button, XV_WLAY_RIGHTOF);
775 add_widgetl (find_dlg,
776 button_new (FIND2_Y-4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON,
777 fbuts[3].text, 0, 0, "button-again"), XV_WLAY_RIGHTOF);
778 add_widgetl (find_dlg,
779 button_new (FIND2_Y-4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON,
780 fbuts[2].text, 0, 0, "button-chdir"), XV_WLAY_CENTERROW);
781
782 status_label = label_new (FIND2_Y-6, 4, _("Searching"), "label-search");
783 add_widgetl (find_dlg, status_label, XV_WLAY_BELOWOF);
784
785 find_list = listbox_new (2, 2, FIND2_X-4, FIND2_Y-9, listbox_finish, 0, "listbox");
786 add_widgetl (find_dlg, find_list, XV_WLAY_EXTENDWIDTH);
787
788 /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
789 find_pattern = pattern;
790 content_pattern = content;
791
792 set_idle_proc (find_dlg, 1);
793 init_find_vars ();
794 push_directory (start_dir);
795
796 #ifdef HAVE_XVIEW
797 xv_post_proc (find_dlg, (void (*)(void *))do_search, (void *)find_dlg);
798 #endif
799 run_dlg (find_dlg);
800
801 return_value = find_dlg->ret_value;
802
803 /* Remove all the items in the stack */
804 while ((dir = pop_directory ()) != NULL)
805 free (dir);
806
807 listbox_get_current (find_list, &file_tmp, &dir_tmp);
808
809 if (dir_tmp)
810 *dirname = strdup (dir_tmp);
811 if (file_tmp)
812 *filename = strdup (file_tmp);
813 if (return_value == B_PANELIZE && *filename){
814 int status, link_to_dir, stalled_link;
815 int next_free = 0;
816 int i;
817 struct stat buf;
818 WLEntry *entry = find_list->list;
819 dir_list *list = &cpanel->dir;
820 char *dir, *name;
821
822 for (i = 0; entry && i < find_list->count; entry = entry->next, i++){
823 char *filename;
824
825 if (content_pattern)
826 filename = strchr (entry->text+4, ':')+1;
827 else
828 filename = entry->text+4;
829
830 if (!entry->text || !entry->data)
831 continue;
832 dir = entry->data;
833 if (dir [0] == '.' && dir [1] == 0)
834 name = strdup (filename);
835 else if (dir [0] == '.' && dir [1] == PATH_SEP)
836 name = get_full_name (dir + 2, filename);
837 else
838 name = get_full_name (dir, filename);
839 status = handle_path (list, name, &buf, next_free, &link_to_dir,
840 &stalled_link);
841 if (status == 0) {
842 free (name);
843 continue;
844 }
845 if (status == -1) {
846 free (name);
847 break;
848 }
849
850 /* don't add files more than once to the panel */
851 if (content_pattern && next_free > 0){
852 if (strcmp (list->list [next_free-1].fname, name) == 0) {
853 free (name);
854 continue;
855 }
856 }
857
858 if (!next_free) /* first turn i.e clean old list */
859 clean_dir (list, cpanel->count);
860 list->list [next_free].fnamelen = strlen (name);
861 list->list [next_free].fname = name;
862 list->list [next_free].cache = NULL;
863 file_mark (cpanel, next_free, 0);
864 list->list [next_free].f.link_to_dir = link_to_dir;
865 list->list [next_free].f.stalled_link = stalled_link;
866 list->list [next_free].buf = buf;
867 next_free++;
868 if (!(next_free & 15))
869 rotate_dash ();
870 }
871 if (next_free){
872 cpanel->count = next_free;
873 cpanel->is_panelized = 1;
874 cpanel->dirs_marked = 0;
875 cpanel->has_dir_sizes = 0;
876 cpanel->marked = 0;
877 cpanel->total = 0;
878 cpanel->top_file = 0;
879 cpanel->selected = 0;
880
881 if (start_dir [0] == PATH_SEP){
882 strcpy (cpanel->cwd, PATH_SEP_STR);
883 chdir (PATH_SEP_STR);
884 }
885 }
886 }
887
888 set_idle_proc (find_dlg, 0);
889 destroy_dlg (find_dlg);
890 do_search (0); /* force do_search to release resources */
891 if (old_dir){
892 free (old_dir);
893 old_dir = 0;
894 }
895 return return_value;
896 }
897
898 void
899 do_find (void)
900 {
901 char *start_dir, *pattern, *content;
902 char *filename, *dirname;
903 int v, dir_and_file_set;
904 int done = 0;
905
906 while (!done){
907 if (!find_parameters (&start_dir, &pattern, &content))
908 break;
909
910 dirname = filename = NULL;
911 is_start = 0;
912 v = find_file (start_dir, pattern, content, &dirname, &filename);
913 free (start_dir);
914 free (pattern);
915
916 if (v == B_ENTER){
917 if (dirname || filename){
918 if (dirname){
919 do_cd (dirname, cd_exact);
920 if (filename)
921 try_to_select (cpanel, filename + (content ?
922 (strchr (filename + 4, ':') - filename + 1) : 4) );
923 } else if (filename)
924 do_cd (filename, cd_exact);
925 paint_panel (cpanel);
926 select_item (cpanel);
927 }
928 if (dirname)
929 free (dirname);
930 if (filename)
931 free (filename);
932 break;
933 }
934 if (content)
935 free (content);
936 dir_and_file_set = dirname && filename;
937 if (dirname) free (dirname);
938 if (filename) free (filename);
939 if (v == B_CANCEL)
940 break;
941
942 if (v == B_PANELIZE){
943 if (dir_and_file_set){
944 try_to_select (cpanel, NULL);
945 paint_panel (cpanel);
946 }
947 break;
948 }
949 }
950 }
951