"Fossies" - the Fresh Open Source Software archive

Member "cftp-0.12/directory.c" of archive cftp-0.12.tar.gz:


/*
  $NiH: directory.c,v 1.20 2002/09/16 12:42:29 dillo Exp $

  directory.c -- handle directory cache
  Copyright (C) 1996-2002 Dieter Baron

  This file is part of cftp, a fullscreen ftp client
  The author can be contacted at <dillo@giga.or.at>

  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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "directory.h"
#include "ftp.h"
#include "bindings.h"
#include "display.h"
#include "options.h"

directory *curdir;

typedef struct dircache {
    directory *dir;

    struct dircache *next, *prev;
} dircache;

dircache *cache_head = NULL, *cache_tail = NULL;
int cache_fill;
int cache_size = 30;

void cache_remove(dircache *d);
void cache_insert(dircache *d);

/* XXX: should be in header file */
void aux_scroll(int top, int sel, int force);



void
dir_free(directory *d)
{
    int i;

    if (d == NULL)
	return;
	
    for (i=0; i<d->len; i++) {
	free(d->line[i].line);
	free(d->line[i].name);
	free(d->line[i].link);
    }
    free(d->line);
    free(d->path);
    free(d);
}



directory *
dir_new(void)
{
    directory *dir;

    if ((dir=malloc(sizeof(*dir))) == NULL)
	return NULL;

    dir->alloc_len = dir->len = dir->top = dir->cur = 0;
    dir->size = sizeof(direntry);
    dir->line = NULL;
    dir->path = NULL;
    dir->sorted = 0;

    return dir;
}



int
dir_add(directory *dir, direntry *e)
{
    int n;
    direntry *line;
    
    if (dir->len >= dir->alloc_len) {
	if (dir->alloc_len == 0)
	    n = 16;
	else if (dir->alloc_len < 1024)
	    n = dir->alloc_len * 2;
	else
	    n = dir->alloc_len + 512;

	if (dir->line == NULL)
	    line = malloc(sizeof(direntry)*n);
	else
	    line = realloc(dir->line, sizeof(direntry)*n);
	if (line == NULL)
	    return -1;
	dir->alloc_len = n;
	dir->line = line;
    }

    n = dir->len++;
    dir->line[n] = *e;
    dir->line[n].pos = n;

    return 0;    
}



directory *
get_dir(char *path, int force)
{
    dircache *d;
    directory *dir;
	
    /* initialize queue */
    if (cache_head == NULL) {
	cache_head = (dircache *)malloc(sizeof(dircache));
	cache_tail = (dircache *)malloc(sizeof(dircache));
	cache_head->prev = cache_tail->prev = cache_head;
	cache_head->next = cache_tail->next = cache_tail;
	cache_head->dir = cache_tail->dir = NULL;
	cache_fill = 0;
    }

    /* find dir */
    for (d=cache_head->next; (d!=cache_tail &&
			      strcmp(path, d->dir->path) != 0);
	 d=d->next)
	;

    if (d != cache_tail) {
	/* found: put d to front of queue and return it */
	cache_remove(d);
	cache_insert(d);

	if (force) {
	    dir = ftp_list(path);
	    if (dir == NULL)
		return NULL;

	    dir_free(d->dir);
	    d->dir = dir;
	}
    }
    else {
	dir = ftp_list(path);
	if (dir == NULL)
	    return NULL;

	/* not found: if cache full, recycle last entry */
	if (cache_fill >= cache_size) {
	    d = cache_tail->prev;
	    cache_remove(d);
	    dir_free(d->dir);
	}
	else {
	    d = (dircache *)malloc(sizeof(dircache));
	    cache_fill++;
	}

	d->dir = dir;
	cache_insert(d);
    }

    dir_sort(d->dir, opt_sort);

    return d->dir;
}



void
cache_remove(dircache *d)
{
    d->prev->next = d->next;
    d->next->prev = d->prev;
    d->next = d->prev = NULL;
}



void
cache_insert(dircache *d)
{
    d->prev = cache_head;
    d->next = cache_head->next;
    cache_head->next->prev = d;
    cache_head->next = d;
}



int
dir_find(directory *dir, char *entry)
{
    int i;

    for (i=0; (i<dir->len &&
	       strcmp(dir->line[i].name, entry)); i++)
	;
    
    if (i == dir->len)
	i = -1;

    return i;
}



static int sort_unsorted(const void *k1, const void *k2);
static int sort_name(const void *k1, const void *k2);
static int sort_date(const void *k1, const void *k2);
static int sort_name_r(const void *k1, const void *k2);
static int sort_date_r(const void *k1, const void *k2);

void
dir_sort(directory *dir, int sort_type)
{
    static int (*func[])(const void *, const void *) = {
	sort_unsorted, sort_name, sort_date, sort_name_r, sort_date_r
    };

    if (dir->sorted == sort_type)
	return;

    qsort(dir->line, dir->len, sizeof(direntry), func[sort_type]);
    dir->sorted = sort_type;

    return;
}



static int
sort_unsorted(const void *k1, const void *k2)
{
    direntry *d1, *d2;

    d1 = (direntry *)k1;
    d2 = (direntry *)k2;

    return d1->pos - d2->pos;
}



static int
sort_name(const void *k1, const void *k2)
{
    direntry *d1, *d2;

    d1 = (direntry *)k1;
    d2 = (direntry *)k2;

    return strcmp(d1->name, d2->name);
}



static int
sort_date(const void *k1, const void *k2)
{
    time_t c;
    direntry *d1, *d2;

    d1 = (direntry *)k1;
    d2 = (direntry *)k2;

    c = d2->mtime - d1->mtime;
    if (c == 0)
	return strcmp(d1->name, d2->name);
    else
	return c;
}    



static int
sort_name_r(const void *k1, const void *k2)
{
    direntry *d1, *d2;

    d1 = (direntry *)k1;
    d2 = (direntry *)k2;

    return strcmp(d2->name, d1->name);
}



static int
sort_date_r(const void *k1, const void *k2)
{
    time_t c;
    direntry *d1, *d2;

    d1 = (direntry *)k1;
    d2 = (direntry *)k2;

    c = d1->mtime - d2->mtime;
    if (c == 0)
	return strcmp(d2->name, d1->name);
    else
	return c;
}    



void
opt_set_sort(int optval, int *optvar)
{
    int cur, i;
    
    if (optval < 0 || optval > 4)
	return;

    *optvar = optval;

    if (curdir && curdir->sorted != optval) {
	cur = curdir->line[curdir->cur].pos;
	dir_sort(curdir, optval);
	for (i=0; i<curdir->len; i++)
	    if (curdir->line[i].pos == cur) {
		cur = i;
		break;
	    }
	if (binding_state == bs_remote)
	    aux_scroll(cur-(win_lines/2), cur, 1);
    }
}