⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 find.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -