📄 find.c
字号:
/* Find file command for the Midnight Commander
Copyright (C) The Free Software Foundation
Written 1995 by Miguel de Icaza
Complete rewrote.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
#include "tty.h"
#include <string.h>
#include <stdio.h>
#ifdef OS2_NT
# include <io.h>
#endif
#include "fs.h"
#include <malloc.h> /* For free() */
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
#include "global.h"
#include "mad.h"
#include "util.h"
#include "win.h"
#include "color.h"
#include "global.h"
extern int verbose; /* Should be in a more sensible header file */
/* Dialog manager and widgets */
#include "dlg.h"
#include "widget.h"
#include "dialog.h" /* For do_refresh() */
#define DIR_H_INCLUDE_HANDLE_DIRENT
#include "dir.h"
#include "panel.h" /* current_panel */
#include "main.h" /* do_cd, try_to_select */
#include "wtools.h"
#include "tree.h"
#include "cmd.h" /* view_file_at_line */
#include "../vfs/vfs.h"
#ifdef HAVE_XVIEW
#include "xvmain.h"
#endif
#ifndef PORT_HAS_FLUSH_EVENTS
# define x_flush_events()
#endif
/* Size of the find parameters window */
#define FIND_Y 12
static int FIND_X = 50;
/* Size of the find window */
#define FIND2_Y LINES-4
static int FIND2_X = 64;
#ifdef HAVE_X
# define FIND2_X_USE 35
#else
# define FIND2_X_USE FIND2_X-20
#endif
/* A couple of extra messages we need */
enum {
B_STOP = B_USER + 1,
B_AGAIN,
B_PANELIZE,
B_TREE,
B_VIEW
};
/* A list of directories to be ignores, separated with ':' */
char *find_ignore_dirs = 0;
static Dlg_head *find_dlg; /* The dialog */
static WInput *in_start; /* Start path */
static WInput *in_name; /* Pattern to search */
static WInput *in_with; /* text inside filename */
static WListbox *find_list; /* Listbox with the file list */
static int running = 0; /* nice flag */
static WButton *stop_button; /* pointer to the stop button */
static WLabel *status_label; /* Finished, Searching etc. */
static char *find_pattern; /* Pattern to search */
static char *content_pattern; /* pattern to search inside files */
static int count; /* Number of files displayed */
static int matches; /* Number of matches */
static int is_start; /* Status of the start/stop toggle button */
int max_loops_in_idle = 10;
static char *old_dir;
/* For nice updating */
static char *rotating_dash = "|/-\\";
/* This keeps track of the directory stack */
typedef struct dir_stack {
char *name;
struct dir_stack *prev;
} dir_stack ;
dir_stack *dir_stack_base = 0;
static struct {
char* text;
int len; /* length including space and brackets */
int x;
} fbuts [] = {
{ N_("&Suspend"), 11, 29 },
{ N_("Con&tinue"), 12, 29 },
{ N_("&Chdir"), 11, 3 },
{ N_("&Again"), 9, 17 },
{ N_("&Quit"), 8, 43 },
{ N_("Pane&lize"), 12, 3 },
{ N_("&View - F3"), 13, 20 },
{ N_("&Edit - F4"), 13, 38 }
};
/*
* find_parameters: gets information from the user
*
* If the return value is true, then the following holds:
*
* START_DIR and PATTERN are pointers to char * and upon return they
* contain the information provided by the user.
*
* CONTENT holds a strdup of the contents specified by the user if he
* asked for them or 0 if not (note, this is different from the
* behavior for the other two parameters.
*
*/
static int
find_parameters (char **start_dir, char **pattern, char **content)
{
int return_value;
char *temp_dir;
static char *in_contents = NULL;
static char *in_start_dir = NULL;
static char *in_start_name = NULL;
static char* labs[] = {N_("Start at:"), N_("Filename:"), N_("Content: ")};
static char* buts[] = {N_("&Ok"), N_("&Tree"), N_("&Cancel")};
static int ilen = 30, istart = 14;
static int b0 = 3, b1 = 16, b2 = 36;
#ifdef ENABLE_NLS
static int i18n_flag = 0;
if (!i18n_flag)
{
register int i = sizeof(labs)/sizeof(labs[0]);
int l1, maxlen = 0;
while (i--)
{
l1 = strlen (labs [i] = _(labs [i]));
if (l1 > maxlen)
maxlen = l1;
}
i = maxlen + ilen + 7;
if (i > FIND_X)
FIND_X = i;
for (i = sizeof(buts)/sizeof(buts[0]), l1 = 0; i--; )
{
l1 += strlen (buts [i] = _(buts [i]));
}
l1 += 21;
if (l1 > FIND_X)
FIND_X = l1;
ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
istart = FIND_X - 3 - ilen;
b1 = b0 + strlen(buts[0]) + 7;
b2 = FIND_X - (strlen(buts[2]) + 6);
i18n_flag = 1;
}
#endif /* ENABLE_NLS */
find_par_start:
if (!in_start_dir)
in_start_dir = strdup (".");
if (!in_start_name)
in_start_name = strdup (easy_patterns ? "*" : ".");
if (!in_contents)
in_contents = strdup ("");
find_dlg = create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
common_dialog_callback, "[Find File]", "findfile",
DLG_CENTER | DLG_GRID);
x_set_dialog_title (find_dlg, _("Find File"));
add_widgetl (find_dlg, button_new (9, b2, B_CANCEL, NORMAL_BUTTON,
buts[2], 0 ,0, "cancel"), XV_WLAY_RIGHTOF);
#ifndef HAVE_GNOME
add_widgetl (find_dlg, button_new (9, b1, B_TREE, NORMAL_BUTTON,
buts[1], 0, 0, "tree"), XV_WLAY_RIGHTOF);
#endif
add_widgetl (find_dlg, button_new (9, b0, B_ENTER, DEFPUSH_BUTTON,
buts[0], 0, 0, "ok"), XV_WLAY_CENTERROW);
in_with = input_new (7, istart, INPUT_COLOR, ilen, in_contents, "content");
add_widgetl (find_dlg, in_with, XV_WLAY_BELOWOF);
in_name = input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name");
add_widgetl (find_dlg, in_name, XV_WLAY_BELOWOF);
in_start = input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start");
add_widgetl (find_dlg, in_start, XV_WLAY_NEXTCOLUMN);
add_widgetl (find_dlg, label_new (7, 3, labs[2], "label-cont"), XV_WLAY_BELOWOF);
add_widgetl (find_dlg, label_new (5, 3, labs[1], "label-file"), XV_WLAY_BELOWOF);
add_widgetl (find_dlg, label_new (3, 3, labs[0], "label-start"), XV_WLAY_NEXTCOLUMN);
run_dlg (find_dlg);
if (find_dlg->ret_value == B_CANCEL)
return_value = 0;
else if (find_dlg->ret_value == B_TREE){
temp_dir = strdup (in_start->buffer);
destroy_dlg (find_dlg);
free (in_start_dir);
if (strcmp (temp_dir, ".") == 0){
free (temp_dir);
temp_dir = strdup (cpanel->cwd);
}
in_start_dir = tree (temp_dir);
if (in_start_dir)
free (temp_dir);
else
in_start_dir = temp_dir;
/* Warning: Dreadful goto */
goto find_par_start;
} else {
return_value = 1;
*start_dir = strdup (in_start->buffer);
*pattern = strdup (in_name->buffer);
free (in_contents);
if (in_with->buffer [0]){
*content = strdup (in_with->buffer);
in_contents = strdup (*content);
} else
*content = in_contents = NULL;
free (in_start_dir);
in_start_dir = strdup (*start_dir);
free (in_start_name);
in_start_name = strdup (*pattern);
}
destroy_dlg (find_dlg);
return return_value;
}
static void
push_directory (char *dir)
{
dir_stack *new;
new = xmalloc (sizeof (dir_stack), "find: push_directory");
new->name = strdup (dir);
new->prev = dir_stack_base;
dir_stack_base = new;
}
static char*
pop_directory (void)
{
char *name;
dir_stack *next;
if (dir_stack_base){
name = dir_stack_base->name;
next = dir_stack_base->prev;
free (dir_stack_base);
dir_stack_base = next;
return name;
} else
return 0;
}
static void
insert_file (char *dir, char *file)
{
char *tmp_name;
static char *dirname;
int i;
if (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
dir++;
i = strlen (dir);
if (i){
if (dir [i - 1] != PATH_SEP){
dir [i] = PATH_SEP;
dir [i + 1] = 0;
}
}
if (old_dir){
if (strcmp (old_dir, dir)){
free (old_dir);
old_dir = strdup (dir);
dirname = listbox_add_item (find_list, 0, 0, dir, 0);
}
} else {
old_dir = strdup (dir);
dirname = listbox_add_item (find_list, 0, 0, dir, 0);
}
tmp_name = copy_strings (" ", file, 0);
listbox_add_item (find_list, 0, 0, tmp_name, dirname);
free (tmp_name);
}
static void
find_add_match (Dlg_head *h, char *dir, char *file)
{
int p = ++matches & 7;
insert_file (dir, file);
/* Scroll nicely */
if (!p)
listbox_select_last (find_list, 1);
else
listbox_select_last (find_list, 0);
#ifndef HAVE_X
/* Updates the current listing */
send_message (h, &find_list->widget, WIDGET_DRAW, 0);
if (p == 7)
mc_refresh ();
#endif
}
char *
locate_egrep (void)
{
char *paths [] = {
"/bin/egrep",
"/usr/bin/egrep",
"/sbin/egrep",
"/usr/sbin/egrep",
NULL
};
struct stat s;
char **p;
for (p = &paths [0]; *p; p++){
if (stat (*p, &s) == 0)
return *p;
}
return "egrep";
}
/*
* search_content:
*
* Search with egrep the global (FIXME) content_pattern string in the
* DIRECTORY/FILE. It will add the found entries to the find listbox.
*/
void
search_content (Dlg_head *h, char *directory, char *filename)
{
struct stat s;
char buffer [128];
char *fname, *p;
int file_fd, pipe, ignoring;
char c;
int i;
pid_t pid;
static char *egrep_path;
fname = get_full_name (directory, filename);
if (mc_stat (fname, &s) != 0 && !S_ISREG (s.st_mode)){
free (fname);
return;
}
if (!S_ISREG (s.st_mode)){
free (fname);
return;
}
file_fd = mc_open (fname, O_RDONLY);
free (fname);
if (file_fd == -1)
return;
if (!egrep_path)
egrep_path = locate_egrep ();
#ifndef GREP_STDIN
pipe = mc_doublepopen (file_fd, -1, &pid, egrep_path, egrep_path, "-n", content_pattern, NULL);
#else /* GREP_STDIN */
pipe = mc_doublepopen (file_fd, -1, &pid, egrep_path, egrep_path, "-n", content_pattern, "-", NULL);
#endif /* GREP STDIN */
if (pipe == -1){
mc_close (file_fd);
return;
}
sprintf (buffer, _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
label_set_text (status_label, buffer);
mc_refresh ();
p = buffer;
ignoring = 0;
enable_interrupt_key ();
got_interrupt ();
while (1){
i = read (pipe, &c, 1);
if (i != 1)
break;
if (c == '\n'){
p = buffer;
ignoring = 0;
}
if (ignoring)
continue;
if (c == ':'){
char *the_name;
*p = 0;
ignoring = 1;
the_name = copy_strings (buffer, ":", filename, NULL);
find_add_match (h, directory, the_name);
free (the_name);
} else {
if (p - buffer < (sizeof (buffer)-1) && ISASCII (c) && isdigit (c))
*p++ = c;
else
*p = 0;
}
}
disable_interrupt_key ();
if (i == -1)
message (1, _(" Find/read "), _(" Problem reading from child "));
mc_doublepclose (pipe, pid);
mc_close (file_fd);
}
static void
do_search (struct Dlg_head *h)
{
static struct dirent *dp = 0;
static DIR *dirp = 0;
static char directory [MC_MAXPATHLEN+2];
struct stat tmp_stat;
static int pos;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -