1
1
Going to be used by the GtkDTree widget, as this is taking lots
of time in the file manager.
Этот коммит содержится в:
Miguel de Icaza 1999-01-09 03:43:05 +00:00
родитель 9d69629866
Коммит 9ea97c5d75
9 изменённых файлов: 758 добавлений и 567 удалений

Просмотреть файл

@ -105,13 +105,13 @@ LOBJS = mad.o
#
# These objects from ../src do depend on HAVE_GNOME
#
OOBJS = dlg.o screen.o widget.o wtools.o info.o boxes.o \
file.o find.o dialog.o key.o chmod.o chown.o view.o \
panelize.o hotlist.o background.o dir.o util.o \
win.o color.o profile.o user.o ext.o setup.o \
subshell.o terms.o achown.o fsusage.o mountlist.o \
@XCURSES@ @REGEX_O@ complete.o command.o \
option.o cmd.o utilunix.o xslint.o gdialogs.o filenot.o
OOBJS = dlg.o screen.o widget.o wtools.o info.o boxes.o \
file.o find.o dialog.o key.o chmod.o chown.o view.o \
panelize.o hotlist.o background.o dir.o util.o \
win.o color.o profile.o user.o ext.o setup.o \
subshell.o terms.o achown.o fsusage.o mountlist.o \
@XCURSES@ @REGEX_O@ complete.o command.o \
option.o cmd.o utilunix.o xslint.o gdialogs.o filenot.o treestore.o
CORBAOBJS = \
main-corba.o \

Просмотреть файл

@ -5,32 +5,10 @@
*/
#include <config.h>
#include <sys/types.h>
#include "tree.h"
#include <gnome.h>
#include "gtree.h"
void
sync_tree (char *pathname)
sync_tree (char *path)
{
}
void
tree_check (const char *dir)
{
}
void
start_tree_check (WTree *tree)
{
}
void
do_tree_check (WTree *tree, const char *subname)
{
}
void
end_tree_check (WTree *tree)
{
}

Просмотреть файл

@ -1,3 +1,23 @@
1999-01-08 Miguel de Icaza <miguel@nuclecu.unam.mx>
* dir.c (handle_dirent): Use the tree_store now.
(handle_path): ditto.
(do_load_dir): ditto.
(do_load_dir): ditto.
(do_reload_dir): ditto.
(do_reload_dir): ditto.
* treestore.c (tree_store_save): New file
(encode): New routine used to encode pathnames in a safe way that
are saved to the mc/.tree file.
(decode): New routine, used to decode the pathnames we encoded in
the step above. Aint love grand?
* tree.c (load_tree): Kill dead code.
Moved all of the tree store information into a new file:
treestore. To be reused by the Gnome code.
1999-01-08 Ilya Zakharevich <ilya@math.ohio-state.edu>
* popt.c: OS/2 and Windows NT portability fix.

Просмотреть файл

@ -25,7 +25,7 @@ SRCS = dir.c util.c main.c screen.c dialog.c key.c keyxdef.c menu.c \
complete.c slint.c command.c cmd.c panelize.c learn.c \
listmode.c utilunix.c background.c rxvt.c \
text.c popt.c findme.c poptparse.c poptconfig.c popthelp.c \
filegui.c filenot.c
filegui.c filenot.c treestore.c
HDRS = color.h file.h mouse.h user.h dialog.h find.h main.h \
util.h dir.h global.h menu.h panel.h win.h mem.h \
@ -36,7 +36,7 @@ HDRS = color.h file.h mouse.h user.h dialog.h find.h main.h \
myslang.h command.h cmd.h tty.h fs.h panelize.h achown.h \
learn.h listmode.h features.inc background.h \
x.h textconf.h i18n.h findme.h popt.h filegui.h keys.h xtty.h \
poptint.h
poptint.h treestore.h
OBJS = dir.o util.o screen.o dialog.o key.o keyxdef.o menu.o \
file.o win.o color.o help.o find.o profile.o user.o view.o \
@ -46,7 +46,7 @@ OBJS = dir.o util.o screen.o dialog.o key.o keyxdef.o menu.o \
mountlist.o @XCURSES@ @REGEX_O@ complete.o slint.o command.o \
cmd.o main.o panelize.o learn.o listmode.o utilunix.o \
background.o rxvt.o text.o popt.o findme.o poptparse.o \
poptconfig.o popthelp.o filegui.o filenot.o
poptconfig.o popthelp.o filegui.o filenot.o treestore.o
#
# Distribution variables

Просмотреть файл

@ -380,7 +380,7 @@ int handle_dirent (dir_list *list, char *filter, struct dirent *dp,
}
if (S_ISDIR (buf1->st_mode))
tree_check (dp->d_name);
tree_store_mark_checked (dp->d_name);
/* A link to a file or a directory? */
*link_to_dir = 0;
@ -422,7 +422,7 @@ int handle_path (dir_list *list, char *path,
return 0;
if (S_ISDIR (buf1->st_mode))
tree_check (path);
tree_store_mark_checked (path);
/* A link to a file or a directory? */
*link_to_dir = 0;
@ -455,7 +455,7 @@ int do_load_dir(dir_list *list, sortfn *sort, int reverse, int case_sensitive, c
struct stat buf;
int dotdot_found = 0;
start_tree_check (NULL);
tree_store_start_check ();
dirp = mc_opendir (".");
if (!dirp){
@ -491,7 +491,7 @@ int do_load_dir(dir_list *list, sortfn *sort, int reverse, int case_sensitive, c
return set_zero_dir (list);
mc_closedir (dirp);
end_tree_check (NULL);
tree_store_end_check ();
return next_free;
}
@ -551,7 +551,7 @@ int do_reload_dir (dir_list *list, sortfn *sort, int count, int rev,
int tmp_len; /* For optimisation */
int dotdot_found = 0;
start_tree_check (NULL);
tree_store_start_check ();
dirp = mc_opendir (".");
if (!dirp) {
clean_dir (list, count);
@ -613,7 +613,7 @@ int do_reload_dir (dir_list *list, sortfn *sort, int count, int rev,
rotate_dash ();
}
mc_closedir (dirp);
end_tree_check (NULL);
tree_store_end_check ();
if (next_free) {
if (!dotdot_found)
add_dotdot_to_list (list, next_free++);

Просмотреть файл

@ -3,7 +3,7 @@
Written: 1994, 1996 Janne Kukonlehto
1997 Norbert Warmuth
1996 Miguel de Icaza
1996, 1999 Miguel de Icaza
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
@ -27,18 +27,8 @@
*/
#include <config.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h> /* For free() and atoi() */
#include <string.h>
#include <errno.h>
#include "tty.h"
#include "mad.h"
#include "global.h"
@ -57,9 +47,6 @@
#include "tree.h"
#include "cmd.h"
#include "../vfs/vfs.h"
#ifdef OS2_NT
# include <io.h>
#endif
extern int command_prompt;
@ -74,16 +61,6 @@ static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
/* "$Id$" */
/* Returns number of common characters */
static inline int str_common (char *s1, char *s2)
{
int result = 0;
while (*s1++ == *s2++)
result++;
return result;
}
static tree_entry *back_ptr (tree_entry *ptr, int *count)
{
int i = 0;
@ -108,185 +85,14 @@ static tree_entry *forw_ptr (tree_entry *ptr, int *count)
return ptr;
}
/* The directory names are arranged in a single linked list in the same
order as they are displayed. When the tree is displayed the expected
order is like this:
/
/bin
/etc
/etc/X11
/etc/rc.d
/etc.old/X11
/etc.old/rc.d
/usr
i.e. the required collating sequence when comparing two directory names is
'\0' < PATH_SEP < all-other-characters-in-encoding-order
Since strcmp doesn't fulfil this requirement we use pathcmp when
inserting directory names into the list. The meaning of the return value
of pathcmp and strcmp are the same (an integer less than, equal to, or
greater than zero if p1 is found to be less than, to match, or be greater
than p2.
*/
static int
pathcmp (const char *p1, const char *p2)
{
for ( ;*p1 == *p2; p1++, p2++)
if (*p1 == '\0' )
return 0;
if (*p1 == '\0')
return -1;
if (*p2 == '\0')
return 1;
if (*p1 == PATH_SEP)
return -1;
if (*p2 == PATH_SEP)
return 1;
return (*p1 - *p2);
}
/* Searches for specified directory */
static tree_entry *whereis (WTree *tree, char *name)
{
tree_entry *current = tree->tree_first;
int flag = -1;
#if 0
if (tree->tree_last){
flag = strcmp (tree->tree_last->name, name);
if (flag <= 0){
current = tree->tree_last;
} else if (tree->selected_ptr){
flag = strcmp (tree->selected_ptr->name, name);
if (flag <= 0){
current = tree->selected_ptr;
}
}
}
#endif
while (current && (flag = pathcmp (current->name, name)) < 0)
current = current->next;
if (flag == 0)
return current;
else
return NULL;
}
/* Add a directory to the list of directories */
tree_entry *tree_add_entry (WTree *tree, char *name)
{
int flag = -1;
tree_entry *current = tree->tree_first;
tree_entry *old = NULL;
tree_entry *new;
int i, len;
int submask = 0;
tree_entry entry;
if (!tree)
return 0;
if (tree->tree_last && tree->tree_last->next)
abort ();
#if 0
if (tree->tree_last){
flag = strcmp (tree->tree_last->name, name);
if (flag <= 0){
current = tree->tree_last;
old = current->prev;
} else if (tree->selected_ptr){
flag = strcmp (tree->selected_ptr->name, name);
if (flag <= 0){
current = tree->selected_ptr;
old = current->prev;
}
}
}
#endif
/* Search for the correct place */
while (current && (flag = pathcmp (current->name, name)) < 0){
old = current;
current = current->next;
}
if (flag == 0)
return current; /* Already in the list */
/* Not in the list -> add it */
new = xmalloc (sizeof (tree_entry), "tree, tree_entry");
if (!current){
/* Append to the end of the list */
if (!tree->tree_first){
/* Empty list */
tree->tree_first = new;
new->prev = NULL;
} else {
old->next = new;
new->prev = old;
}
new->next = NULL;
tree->tree_last = new;
} else {
/* Insert in to the middle of the list */
new->prev = old;
if (old){
/* Yes, in the middle */
new->next = old->next;
old->next = new;
} else {
/* Nope, in the beginning of the list */
new->next = tree->tree_first;
tree->tree_first = new;
}
new->next->prev = new;
}
/* tree_count++; */
/* Calculate attributes */
new->name = strdup (name);
len = strlen (new->name);
new->sublevel = 0;
for (i = 0; i < len; i++)
if (new->name [i] == PATH_SEP){
new->sublevel++;
new->subname = new->name + i + 1;
}
if (new->next)
submask = new->next->submask;
else
submask = 0;
submask |= 1 << new->sublevel;
submask &= (2 << new->sublevel) - 1;
new->submask = submask;
new->mark = 0;
/* Correct the submasks of the previous entries */
current = new->prev;
while (current && current->sublevel > new->sublevel){
current->submask |= 1 << new->sublevel;
current = current->prev;
}
/* The entry has now been added */
if (new->sublevel > 1){
/* Let's check if the parent directory is in the tree */
char *parent = strdup (new->name);
int i;
for (i = strlen (parent) - 1; i > 1; i--){
if (parent [i] == PATH_SEP){
parent [i] = 0;
tree_add_entry (tree, parent);
break;
}
}
free (parent);
}
return new;
return tree_store_add_entry (name);
}
#if 0
@ -300,16 +106,16 @@ static tree_entry *tree_append_entry (WTree *tree, char *name)
/* We assume the directory is not yet in the list */
new = xmalloc (sizeof (tree_entry), "tree, tree_entry");
if (!tree->tree_first){
if (!tree->store->tree_first){
/* Empty list */
tree->tree_first = new;
tree->store->tree_first = new;
new->prev = NULL;
} else {
tree->tree_last->next = new;
new->prev = tree->tree_last;
}
new->next = NULL;
tree->tree_last = new;
tree->store->tree_last = new;
/* Calculate attributes */
new->name = strdup (name);
@ -337,306 +143,71 @@ static tree_entry *tree_append_entry (WTree *tree, char *name)
}
#endif
static void remove_entry (WTree *tree, tree_entry *entry)
void
remove_callback (tree_entry *entry, void *data)
{
tree_entry *current = entry->prev;
long submask = 0;
WTree *tree = data;
if (tree->selected_ptr == entry){
if (tree->selected_ptr->next)
tree->selected_ptr = tree->selected_ptr->next;
else
tree->selected_ptr = tree->selected_ptr->prev;
}
/* Correct the submasks of the previous entries */
if (entry->next)
submask = entry->next->submask;
while (current && current->sublevel > entry->sublevel){
submask |= 1 << current->sublevel;
submask &= (2 << current->sublevel) - 1;
current->submask = submask;
current = current->prev;
}
/* Unlink the entry from the list */
if (entry->prev)
entry->prev->next = entry->next;
else
tree->tree_first = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
else
tree->tree_last = entry->prev;
/* tree_count--; */
/* Free the memory used by the entry */
free (entry->name);
free (entry);
if (tree->selected_ptr == entry){
if (tree->selected_ptr->next)
tree->selected_ptr = tree->selected_ptr->next;
else
tree->selected_ptr = tree->selected_ptr->prev;
}
}
void tree_remove_entry (WTree *tree, char *name)
{
tree_entry *current, *base, *old;
int len, base_sublevel;
/* Miguel Ugly hack */
if (name [0] == PATH_SEP && name [1] == 0)
return;
/* Miguel Ugly hack end */
base = whereis (tree, name);
if (!base)
return; /* Doesn't exist */
if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
base_sublevel = base->sublevel;
else
base_sublevel = base->sublevel + 1;
len = strlen (base->name);
current = base->next;
while (current
&& strncmp (current->name, base->name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP)){
old = current;
current = current->next;
remove_entry (tree, old);
}
remove_entry (tree, base);
tree_store_remove_entry (name);
}
void tree_destroy (WTree *tree)
{
tree_entry *current, *old;
save_tree (tree);
current = tree->tree_first;
while (current){
old = current;
current = current->next;
free (old->name);
free (old);
}
tree_store_destroy ();
if (tree->tree_shown){
free (tree->tree_shown);
tree->tree_shown = 0;
}
tree->selected_ptr = tree->tree_first = tree->tree_last = NULL;
}
/* Mark the subdirectories of the current directory for delete */
void start_tree_check (WTree *tree)
{
tree_entry *current;
int len;
if (!tree)
tree = (WTree *) find_widget_type (current_dlg, tcallback);
if (!tree)
return;
/* Search for the start of subdirectories */
mc_get_current_wd (tree->check_name, MC_MAXPATHLEN);
tree->check_start = NULL;
current = whereis (tree, tree->check_name);
if (!current){
/* Cwd doesn't exist -> add it */
current = tree_add_entry (tree, tree->check_name);
return;
}
/* Mark old subdirectories for delete */
tree->check_start = current->next;
len = strlen (tree->check_name);
current = tree->check_start;
while (current
&& strncmp (current->name, tree->check_name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
current->mark = 1;
current = current->next;
}
}
/* This subdirectory exists -> clear deletion mark */
void do_tree_check (WTree *tree, const char *subname)
{
char *name;
tree_entry *current, *base;
int flag = 1, len;
/* Calculate the full name of the subdirectory */
if (subname [0] == '.' &&
(subname [1] == 0 || (subname [1] == '.' && subname [2] == 0)))
return;
if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
name = copy_strings (PATH_SEP_STR, subname, 0);
else
name = concat_dir_and_file (tree->check_name, subname);
/* Search for the subdirectory */
current = tree->check_start;
while (current && (flag = pathcmp (current->name, name)) < 0)
current = current->next;
if (flag != 0)
/* Doesn't exist -> add it */
current = tree_add_entry (tree, name);
free (name);
/* Clear the deletion mark from the subdirectory and its children */
base = current;
if (base){
len = strlen (base->name);
base->mark = 0;
current = base->next;
while (current
&& strncmp (current->name, base->name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
current->mark = 0;
current = current->next;
}
}
}
/* Tree check searchs a tree widget in the current dialog and
* if it finds it, it calls do_tree_check on the subname
*/
void tree_check (const char *subname)
{
WTree *tree;
tree = (WTree *) find_widget_type (current_dlg, tcallback);
if (!tree)
return;
do_tree_check (tree, subname);
}
/* Delete subdirectories which still have the deletion mark */
void end_tree_check (WTree *tree)
{
tree_entry *current, *old;
int len;
if (!tree)
tree = (WTree *) find_widget_type (current_dlg, tcallback);
if (!tree)
return;
/* Check delete marks and delete if found */
len = strlen (tree->check_name);
current = tree->check_start;
while (current
&& strncmp (current->name, tree->check_name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
old = current;
current = current->next;
if (old->mark)
remove_entry (tree, old);
}
tree->selected_ptr = NULL;
}
/* Loads the .mc.tree file */
void load_tree (WTree *tree)
{
char *filename;
FILE *file;
char name [MC_MAXPATHLEN], oldname[MC_MAXPATHLEN];
char *different;
int len, common;
filename = concat_dir_and_file (home_dir, MC_TREE);
file = fopen (filename, "r");
free (filename);
if (!file){
/* No new tree file -> let's try the old file */
filename = concat_dir_and_file (home_dir, MC_TREE);
file = fopen (filename, "r");
free (filename);
}
int v;
if (file){
/* File open -> read contents */
oldname [0] = 0;
while (fgets (name, MC_MAXPATHLEN, file)){
len = strlen (name);
if (name [len - 1] == '\n'){
name [--len] = 0;
}
#ifdef OS2_NT
/* .ado: Drives for NT and OS/2 */
if ((len > 2) &&
isalpha(name[0]) &&
(name[1] == ':') &&
(name[2] == '\\')) {
tree_add_entry (tree, name);
strcpy (oldname, name);
} else
#endif
/* UNIX Version */
if (name [0] != PATH_SEP){
/* Clear-text decompression */
char *s = strtok (name, " ");
filename = concat_dir_and_file (home_dir, MC_TREE);
v = tree_store_load (filename);
free (filename);
if (s){
common = atoi (s);
different = strtok (NULL, "");
if (different){
strcpy (oldname + common, different);
tree_add_entry (tree, oldname);
}
}
} else {
tree_add_entry (tree, name);
strcpy (oldname, name);
}
}
fclose (file);
}
if (!tree->tree_first){
/* Nothing loaded -> let's add some standard directories */
tree_add_entry (tree, PATH_SEP_STR);
tree->selected_ptr = tree->tree_first;
tree_rescan_cmd (tree);
tree_add_entry (tree, home_dir);
tree_chdir (tree, home_dir);
tree_rescan_cmd (tree);
tree->selected_ptr = tree->store->tree_first;
if (!v){
tree_store_add_entry (home_dir);
tree_chdir (tree, home_dir);
tree_store_rescan (home_dir);
}
}
/* Save the .mc.tree file */
void save_tree (WTree *tree)
{
tree_entry *current;
int error;
char *filename;
FILE *file;
int i, common;
filename = concat_dir_and_file (home_dir, MC_TREE);
file = fopen (filename, "w");
error = tree_store_save (filename);
free (filename);
if (!file){
if (error){
fprintf (stderr, _("Can't open the %s file for writing:\n%s\n"), MC_TREE,
unix_error_string (errno));
unix_error_string (error));
return;
}
current = tree->tree_first;
while (current){
if (current->prev && (common = str_common (current->prev->name, current->name)) > 2)
/* Clear-text compression */
i = fprintf (file, "%d %s\n", common, current->name + common);
else
i = fprintf (file, "%s\n", current->name);
if (i == EOF){
fprintf (stderr, _("Can't write to the %s file:\n%s\n"), MC_TREE,
unix_error_string (errno));
break;
}
current = current->next;
}
fclose (file);
}
static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
@ -697,12 +268,12 @@ void show_tree (WTree *tree)
"tree, show_tree");
for (i = 0; i < tree_lines; i++)
tree->tree_shown [i] = NULL;
if (tree->tree_first)
topsublevel = tree->tree_first->sublevel;
if (tree->store->tree_first)
topsublevel = tree->store->tree_first->sublevel;
else
topsublevel = 0;
if (!tree->selected_ptr){
tree->selected_ptr = tree->tree_first;
tree->selected_ptr = tree->store->tree_first;
tree->topdiff = 0;
}
current = tree->selected_ptr;
@ -915,7 +486,7 @@ int tree_move_to_parent (WTree *tree)
tree->topdiff--;
}
if (!current)
current = tree->tree_first;
current = tree->store->tree_first;
tree->selected_ptr = current;
check_focus (tree);
return tree->selected_ptr != old;
@ -923,13 +494,13 @@ int tree_move_to_parent (WTree *tree)
void tree_move_to_top (WTree *tree)
{
tree->selected_ptr = tree->tree_first;
tree->selected_ptr = tree->store->tree_first;
tree->topdiff = 0;
}
void tree_move_to_bottom (WTree *tree)
{
tree->selected_ptr = tree->tree_last;
tree->selected_ptr = tree->store->tree_last;
tree->topdiff = tlines (tree) - 3 - 1;
}
@ -937,7 +508,7 @@ void tree_chdir (WTree *tree, char *dir)
{
tree_entry *current;
current = whereis (tree, dir);
current = tree_store_whereis (dir);
if (current){
tree->selected_ptr = current;
check_focus (tree);
@ -1019,7 +590,7 @@ int search_tree (WTree *tree, char *text)
}
current = current->next;
if (!current){
current = tree->tree_first;
current = tree->store->tree_first;
wrapped = 1;
}
tree->topdiff++;
@ -1052,26 +623,13 @@ static void tree_do_search (WTree *tree, int key)
void tree_rescan_cmd (WTree *tree)
{
DIR *dirp;
struct dirent *dp;
struct stat buf;
char old_dir [MC_MAXPATHLEN];
if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
mc_chdir (tree->selected_ptr->name))
return;
start_tree_check (tree);
dirp = opendir (".");
if (dirp){
for (dp = readdir (dirp); dp; dp = readdir (dirp)){
lstat (dp->d_name, &buf);
if (S_ISDIR (buf.st_mode))
do_tree_check (tree, dp->d_name);
}
closedir (dirp);
}
end_tree_check (tree);
tree_store_rescan (tree->selected_ptr->name);
mc_chdir (old_dir);
}
@ -1082,15 +640,6 @@ int tree_forget_cmd (WTree *tree)
return 1;
}
#if 0
static int toggle_nav_mode (void)
{
tree_navigation_flag = 1 - tree_navigation_flag;
return 1;
}
#endif
void tree_copy (WTree *tree, char *default_dest)
{
char *dest;
@ -1220,18 +769,6 @@ tree_rmdir_cmd (WTree *tree)
return;
}
#if 0
static int
tree_quit_cmd (void)
{
/*
FIXME
return done = 1;
*/
return 1;
}
#endif
static void set_navig_label (Dlg_head *h);
static void
@ -1350,7 +887,7 @@ start_search (WTree *tree)
if (tree->searching){
if (tree->selected_ptr == tree->tree_last)
if (tree->selected_ptr == tree->store->tree_last)
tree_move_to_top(tree);
else {
/* set navigation mode temporarily to 'Static' because in
@ -1523,9 +1060,11 @@ tree_new (int is_panel, int y, int x, int lines, int cols)
(destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
tree->is_panel = is_panel;
tree->selected_ptr = 0;
tree->store = tree_store_init ();
tree_store_add_entry_remove_hook (remove_callback, tree);
tree->tree_shown = 0;
tree->search_buffer [0] = 0;
tree->tree_first = tree->tree_last = 0;
tree->topdiff = tree->widget.lines / 2;
tree->searching = 0;
tree->done = 0;

Просмотреть файл

@ -1,26 +1,15 @@
#ifndef __TREE_H
#define __TREE_H
typedef struct tree_entry {
char *name; /* The full path of directory */
int sublevel; /* Number of parent directories (slashes) */
long submask; /* Bitmask of existing sublevels after this entry */
char *subname; /* The last part of name (the actual name) */
int mark; /* Flag: Is this entry marked (e. g. for delete)? */
struct tree_entry *next; /* Next item in the list */
struct tree_entry *prev; /* Previous item in the list */
} tree_entry;
#include "treestore.h"
#include "dlg.h"
typedef struct {
Widget widget;
tree_entry *tree_first; /* First entry in the list */
tree_entry *tree_last; /* Last entry in the list */
TreeStore *store;
tree_entry *selected_ptr; /* The selected directory */
char search_buffer [256]; /* Current search string */
int done; /* Flag: exit tree */
char check_name [MC_MAXPATHLEN];/* Directory which is been checked */
tree_entry *check_start; /* Start of checked subdirectories */
tree_entry **tree_shown; /* Entries currently on screen */
int is_panel; /* panel or plain widget flag */
int active; /* if it's currently selected */
@ -47,10 +36,6 @@ int search_tree (WTree *tree, char *text);
tree_entry *tree_add_entry (WTree *tree, char *name);
void tree_remove_entry (WTree *tree, char *name);
void tree_destroy (WTree *tree);
void tree_check (const char *subname);
void start_tree_check (WTree *tree);
void do_tree_check (WTree *tree, const char *subname);
void end_tree_check (WTree *tree);
void tree_move_backward (WTree *tree, int i);
void tree_move_forward (WTree *tree, int i);

631
src/treestore.c Обычный файл
Просмотреть файл

@ -0,0 +1,631 @@
/*
* Tree Store
*
* Contains a storage of the file system tree representation
*
Copyright (C) 1994, 1995, 1996, 1997 The Free Software Foundation
Written: 1994, 1996 Janne Kukonlehto
1997 Norbert Warmuth
1996, 1999 Miguel de Icaza
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.
This module has been converted to be a widget.
The program load and saves the tree each time the tree widget is
created and destroyed. This is required for the future vfs layer,
it will be possible to have tree views over virtual file systems.
*/
#include <config.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "fs.h"
#include "util.h"
#include "treestore.h"
#ifdef OS2_NT
# include <io.h>
#endif
static TreeStore ts;
/* Returns number of common characters */
static int str_common (char *s1, char *s2)
{
int result = 0;
while (*s1++ == *s2++)
result++;
return result;
}
/* The directory names are arranged in a single linked list in the same
order as they are displayed. When the tree is displayed the expected
order is like this:
/
/bin
/etc
/etc/X11
/etc/rc.d
/etc.old/X11
/etc.old/rc.d
/usr
i.e. the required collating sequence when comparing two directory names is
'\0' < PATH_SEP < all-other-characters-in-encoding-order
Since strcmp doesn't fulfil this requirement we use pathcmp when
inserting directory names into the list. The meaning of the return value
of pathcmp and strcmp are the same (an integer less than, equal to, or
greater than zero if p1 is found to be less than, to match, or be greater
than p2.
*/
static int
pathcmp (const char *p1, const char *p2)
{
for ( ;*p1 == *p2; p1++, p2++)
if (*p1 == '\0' )
return 0;
if (*p1 == '\0')
return -1;
if (*p2 == '\0')
return 1;
if (*p1 == PATH_SEP)
return -1;
if (*p2 == PATH_SEP)
return 1;
return (*p1 - *p2);
}
/* Searches for specified directory */
tree_entry *
tree_store_whereis (char *name)
{
tree_entry *current = ts.tree_first;
int flag = -1;
while (current && (flag = pathcmp (current->name, name)) < 0)
current = current->next;
if (flag == 0)
return current;
else
return NULL;
}
TreeStore *
tree_store_init (void)
{
ts.tree_first = 0;
ts.tree_last = 0;
ts.refcount++;
return &ts;
}
void
tree_store_destroy (void)
{
tree_entry *current, *old;
ts.refcount--;
current = ts.tree_first;
while (current){
old = current;
current = current->next;
free (old->name);
free (old);
}
ts.tree_first = NULL;
ts.tree_last = NULL;
ts.loaded = FALSE;
}
static char *
decode (char *buffer)
{
char *res = strdup (buffer);
char *p, *q;
for (p = q = res; *p; p++, q++){
if (*p == '\n'){
*q = 0;
return res;
}
if (*p != '\\'){
*q = *p;
continue;
}
p++;
switch (*p){
case 'n':
*q = '\n';
break;
case '\\':
*q = '\\';
break;
}
}
*q = *p;
return res;
}
int
tree_store_load (char *name)
{
FILE *file;
char buffer [MC_MAXPATHLEN], oldname[MC_MAXPATHLEN];
char *different;
int len, common;
g_return_if_fail (name != NULL);
if (ts.loaded)
return TRUE;
file = fopen (name, "r");
if (file){
ts.loaded = TRUE;
/* File open -> read contents */
oldname [0] = 0;
while (fgets (buffer, MC_MAXPATHLEN, file)){
char *name = decode (buffer);
len = strlen (name);
#ifdef OS2_NT
/* .ado: Drives for NT and OS/2 */
if ((len > 2) &&
isalpha(name[0]) &&
(name[1] == ':') &&
(name[2] == '\\')) {
tree_store_add_entry (name);
strcpy (oldname, name);
} else
#endif
/* UNIX Version */
if (name [0] != PATH_SEP){
/* Clear-text decompression */
char *s = strtok (name, " ");
if (s){
common = atoi (s);
different = strtok (NULL, "");
if (different){
strcpy (oldname + common, different);
tree_store_add_entry (oldname);
}
}
} else {
tree_store_add_entry (name);
strcpy (oldname, name);
}
}
fclose (file);
}
/* Nothing loaded, we add some standard directories */
if (!ts.tree_first){
tree_store_add_entry (PATH_SEP_STR);
tree_store_rescan (PATH_SEP_STR);
}
return TRUE;
}
static char *
encode (char *string)
{
int special_chars;
char *p, *q;
char *res;
for (special_chars = 0, p = string; *p; p++){
if (*p == '\n' || *p == '\\')
special_chars++;
}
res = malloc (p - string + special_chars + 1);
for (p = string, q = res; *p; p++, q++){
if (*p != '\n' && *p != '\\'){
*q = *p;
continue;
}
*q++ = '\\';
switch (*p){
case '\n':
*q = 'n';
break;
case '\\':
*q = '\\';
break;
}
}
*q = 0;
return res;
}
int
tree_store_save (char *name)
{
tree_entry *current;
FILE *file;
file = fopen (name, "w");
if (!file)
return errno;
current = ts.tree_first;
while (current){
int i, common;
/* Clear-text compression */
if (current->prev && (common = str_common (current->prev->name, current->name)) > 2){
char *encoded = encode (current->name + common);
i = fprintf (file, "%d %s\n", common, encoded);
free (encoded);
} else {
char *encoded = encode (current->name);
i = fprintf (file, "%s\n", encoded);
free (encoded);
}
if (i == EOF){
fprintf (stderr, _("Can't write to the %s file:\n%s\n"), name,
unix_error_string (errno));
break;
}
current = current->next;
}
fclose (file);
return 0;
}
tree_entry *
tree_store_add_entry (char *name)
{
int flag = -1;
tree_entry *current = ts.tree_first;
tree_entry *old = NULL;
tree_entry *new;
int i, len;
int submask = 0;
if (ts.tree_last && ts.tree_last->next)
abort ();
/* Search for the correct place */
while (current && (flag = pathcmp (current->name, name)) < 0){
old = current;
current = current->next;
}
if (flag == 0)
return current; /* Already in the list */
/* Not in the list -> add it */
new = xmalloc (sizeof (tree_entry), "ts, tree_entry");
if (!current){
/* Append to the end of the list */
if (!ts.tree_first){
/* Empty list */
ts.tree_first = new;
new->prev = NULL;
} else {
old->next = new;
new->prev = old;
}
new->next = NULL;
ts.tree_last = new;
} else {
/* Insert in to the middle of the list */
new->prev = old;
if (old){
/* Yes, in the middle */
new->next = old->next;
old->next = new;
} else {
/* Nope, in the beginning of the list */
new->next = ts.tree_first;
ts.tree_first = new;
}
new->next->prev = new;
}
/* Calculate attributes */
new->name = strdup (name);
len = strlen (new->name);
new->sublevel = 0;
for (i = 0; i < len; i++)
if (new->name [i] == PATH_SEP){
new->sublevel++;
new->subname = new->name + i + 1;
}
if (new->next)
submask = new->next->submask;
else
submask = 0;
submask |= 1 << new->sublevel;
submask &= (2 << new->sublevel) - 1;
new->submask = submask;
new->mark = 0;
/* Correct the submasks of the previous entries */
current = new->prev;
while (current && current->sublevel > new->sublevel){
current->submask |= 1 << new->sublevel;
current = current->prev;
}
/* The entry has now been added */
if (new->sublevel > 1){
/* Let's check if the parent directory is in the tree */
char *parent = strdup (new->name);
int i;
for (i = strlen (parent) - 1; i > 1; i--){
if (parent [i] == PATH_SEP){
parent [i] = 0;
tree_store_add_entry (parent);
break;
}
}
free (parent);
}
return new;
}
tree_entry *
remove_entry (tree_entry *entry)
{
tree_entry *current = entry->prev;
long submask = 0;
tree_entry *ret = NULL;
tree_store_notify_remove (entry);
/* Correct the submasks of the previous entries */
if (entry->next)
submask = entry->next->submask;
while (current && current->sublevel > entry->sublevel){
submask |= 1 << current->sublevel;
submask &= (2 << current->sublevel) - 1;
current->submask = submask;
current = current->prev;
}
/* Unlink the entry from the list */
if (entry->prev)
entry->prev->next = entry->next;
else
ts.tree_first = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
else
ts.tree_last = entry->prev;
/* Free the memory used by the entry */
free (entry->name);
free (entry);
return ret;
}
void
tree_store_remove_entry (char *name)
{
tree_entry *current, *base, *old;
int len, base_sublevel;
g_return_if_fail (name != NULL);
/* Miguel Ugly hack */
if (name [0] == PATH_SEP && name [1] == 0)
return;
/* Miguel Ugly hack end */
base = tree_store_whereis (name);
if (!base)
return; /* Doesn't exist */
if (ts.check_name [0] == PATH_SEP && ts.check_name [1] == 0)
base_sublevel = base->sublevel;
else
base_sublevel = base->sublevel + 1;
len = strlen (base->name);
current = base->next;
while (current
&& strncmp (current->name, base->name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP)){
old = current;
current = current->next;
remove_entry (old);
}
remove_entry (base);
return;
}
/* This subdirectory exists -> clear deletion mark */
void
tree_store_mark_checked (const char *subname)
{
char *name;
tree_entry *current, *base;
int flag = 1, len;
if (!ts.loaded)
return;
/* Calculate the full name of the subdirectory */
if (subname [0] == '.' &&
(subname [1] == 0 || (subname [1] == '.' && subname [2] == 0)))
return;
if (ts.check_name [0] == PATH_SEP && ts.check_name [1] == 0)
name = copy_strings (PATH_SEP_STR, subname, 0);
else
name = concat_dir_and_file (ts.check_name, subname);
/* Search for the subdirectory */
current = ts.check_start;
while (current && (flag = pathcmp (current->name, name)) < 0)
current = current->next;
if (flag != 0)
/* Doesn't exist -> add it */
current = tree_store_add_entry (name);
free (name);
/* Clear the deletion mark from the subdirectory and its children */
base = current;
if (base){
len = strlen (base->name);
base->mark = 0;
current = base->next;
while (current
&& strncmp (current->name, base->name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
current->mark = 0;
current = current->next;
}
}
}
/* Mark the subdirectories of the current directory for delete */
void
tree_store_start_check (void)
{
tree_entry *current;
int len;
if (!ts.loaded)
return;
/* Search for the start of subdirectories */
mc_get_current_wd (ts.check_name, MC_MAXPATHLEN);
ts.check_start = NULL;
current = tree_store_whereis (ts.check_name);
if (!current){
/* Cwd doesn't exist -> add it */
current = tree_store_add_entry (ts.check_name);
return;
}
/* Mark old subdirectories for delete */
ts.check_start = current->next;
len = strlen (ts.check_name);
current = ts.check_start;
while (current
&& strncmp (current->name, ts.check_name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
current->mark = 1;
current = current->next;
}
}
/* Delete subdirectories which still have the deletion mark */
void
tree_store_end_check (void)
{
tree_entry *current, *old;
int len;
if (!ts.loaded)
return;
/* Check delete marks and delete if found */
len = strlen (ts.check_name);
current = ts.check_start;
while (current
&& strncmp (current->name, ts.check_name, len) == 0
&& (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
old = current;
current = current->next;
if (old->mark)
remove_entry (old);
}
}
void
tree_store_rescan (char *dir)
{
DIR *dirp;
struct dirent *dp;
struct stat buf;
tree_store_start_check ();
dirp = opendir (dir);
if (dirp){
for (dp = readdir (dirp); dp; dp = readdir (dirp)){
lstat (dp->d_name, &buf);
if (S_ISDIR (buf.st_mode))
tree_store_mark_checked (dp->d_name);
}
closedir (dirp);
}
tree_store_end_check ();
}
static Hook *remove_entry_hooks;
void
tree_store_add_entry_remove_hook (tree_store_remove_fn callback, void *data)
{
add_hook (&remove_entry_hooks, (void (*)(void *))callback, data);
}
void
tree_store_notify_remove (tree_entry *entry)
{
Hook *p = remove_entry_hooks;
tree_store_remove_fn r;
while (p){
r = (tree_store_remove_fn) p->hook_fn;
r (entry, p->hook_data);
p = p->next;
}
}

38
src/treestore.h Обычный файл
Просмотреть файл

@ -0,0 +1,38 @@
#ifndef __TREE_STORE_H
#define __TREE_STORE_H
typedef struct tree_entry {
char *name; /* The full path of directory */
int sublevel; /* Number of parent directories (slashes) */
long submask; /* Bitmask of existing sublevels after this entry */
char *subname; /* The last part of name (the actual name) */
int mark; /* Flag: Is this entry marked (e. g. for delete)? */
struct tree_entry *next; /* Next item in the list */
struct tree_entry *prev; /* Previous item in the list */
} tree_entry;
typedef struct {
int refcount;
tree_entry *tree_first; /* First entry in the list */
tree_entry *tree_last; /* Last entry in the list */
tree_entry *check_start; /* Start of checked subdirectories */
char check_name [MC_MAXPATHLEN];/* Directory which is been checked */
int loaded;
} TreeStore;
TreeStore *tree_store_init (void);
int tree_store_load (char *name);
int tree_store_save (char *name);
tree_entry *tree_store_add_entry (char *name);
void tree_store_remove_entry (char *name);
void tree_store_destroy (void);
void tree_store_start_check (void);
void tree_store_mark_checked (const char *subname);
void tree_store_end_check (void);
tree_entry *tree_store_whereis (char *name);
void tree_store_rescan (char *dir);
typedef void (*tree_store_remove_fn)(tree_entry *tree, void *data);
void tree_store_add_entry_remove_hook (tree_store_remove_fn callback, void *data);
#endif