/*
$NiH: tag.c,v 1.36 2002/09/16 12:42:44 dillo Exp $
tag.c -- tagging
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 "config.h"
#ifdef HAVE_BASENAME
# ifdef HAVE_LIBGEN_H
# include <libgen.h>
# endif
#else
char *basename(char *);
#endif
#include "tag.h"
#include "directory.h"
#include "options.h"
#include "list.h"
#include "util.h"
#include "bindings.h"
struct taglist tags;
struct tagentry tags_s;
static int _tag_insert(int n, struct tagentry *t, char *file,
long size, char type);
static int _tag_update_curdir(struct tagentry *u, enum tagopt what);
int
tag_init(void)
{
tags_s.next = tags_s.prev = &tags_s;
tags.len = tags.cur = tags.top = 0;
tags.size = sizeof(struct tagentry);
tags.reallen = 1024;
if ((tags.line=(struct tagentry *)malloc(tags.reallen
*sizeof(struct tagentry)))
== NULL)
return -1;
return 0;
}
void
change_curdir(directory *dir)
{
struct tagentry *t;
int i, cmp;
if (curdir) {
for (i=0; i<curdir->len; i++)
curdir->line[i].line[0] = ' ';
cmp = 1;
for (t=tags_s.next; t != &tags_s && cmp >= 0; t = t->next) {
cmp = strncmp(dir->path, t->name, t->dirl);
if (cmp == 0 && (i=dir_find(dir, t->file)) >= 0) {
dir->line[i].line[0] = opt_tagchar;
}
}
curdir->top = curdir->cur = 0;
}
curdir = dir;
if (binding_state == bs_remote)
list = (struct list *)curdir;
}
int
tag_file(char *dir, char *file, long size, char type, enum tagopt what)
{
char *canon;
struct tagentry *t;
int cmp;
canon = NULL;
if (dir == NULL)
canon = canonical(file, NULL);
else {
if ((canon=(char *)malloc(strlen(dir)+strlen(file)+2)) == NULL)
return 0;
sprintf(canon, "%s%s%s", dir,
(strcmp(dir, "/") == 0 ? "" : "/"), file);
}
cmp = 1;
for (t=tags_s.next; t != &tags_s; t = t->next) {
if ((cmp=strcmp(canon, t->name)) <= 0)
break;
}
if (t != &tags_s && cmp == 0) {
if (what == TAG_ON) {
free(canon);
return 0;
}
tag_delete(t-tags.line);
return -1;
}
else {
if (what == TAG_OFF) {
free(canon);
return 0;
}
_tag_insert(tags.len, t->prev, canon, size, type);
return 1;
}
}
void
tag_clear(void)
{
int i;
tags_s.next = tags_s.prev = &tags_s;
for (i=0; i<tags.len; i++) {
_tag_update_curdir(&tags.line[i], TAG_OFF);
free(tags.line[i].line);
free(tags.line[i].name);
}
tags.len = 0;
}
void
tag_delete(int n)
{
int i;
struct tagentry *t;
t = tags.line+n;
_tag_update_curdir(t, TAG_OFF);
free(t->line);
free(t->name);
t->next->prev = t->prev;
t->prev->next = t->next;
--tags.len;
for (i=n; i<tags.len; i++) {
tags.line[i] = tags.line[i+1];
tags.line[i].prev->next--;
tags.line[i].next->prev--;
}
}
static int
_tag_insert(int n, struct tagentry *t, char *file, long size, char type)
{
int i;
char *line;
struct tagentry *u;
if ((line=(char *)malloc(strlen(file)+14)) == NULL)
return -1;
if (tags.len >= tags.reallen) {
tags.reallen += 1024;
if ((u=(struct tagentry *)realloc(tags.line, tags.reallen
*sizeof(struct tagentry)))
== NULL)
return -1;
if (u != tags.line) {
/* tags cannot be empty since tags.line is full */
tags_s.next = u + (tags_s.next - &tags.line[0]);
tags_s.prev = u + (tags_s.prev - &tags.line[0]);
for (i=0; i<tags.len; i++) {
if (u[i].prev != &tags_s)
u[i].prev = u + (tags.line[i].prev - &tags.line[0]);
if (u[i].next != &tags_s)
u[i].next = u + (tags.line[i].next - &tags.line[0]);
}
tags.line = u;
}
}
for (i=tags.len; i>n; --i) {
tags.line[i].prev->next++;
tags.line[i].next->prev++;
tags.line[i+1] = tags.line[i];
}
sprintf(line, "%8ld %c %s", size, type, file);
u = tags.line+n;
u->line = line;
u->name = file;
u->file = basename(file);
u->dirl = tags.line[n].file - file;
if (u->dirl > 1)
--u->dirl;
u->size = size;
u->type = type;
u->next = t->next;
u->prev = t;
t->next = u;
u->next->prev = u;
_tag_update_curdir(u, TAG_ON);
tags.len++;
return 0;
}
static int
_tag_update_curdir(struct tagentry *u, enum tagopt what)
{
int i;
if (strlen(curdir->path) == u->dirl
&& strncmp(curdir->path, u->name, u->dirl) == 0) {
i = dir_find(curdir, u->file);
if (i >= 0
&& (curdir->line[i].line[0] !=
(what == TAG_ON) ? opt_tagchar : ' ')) {
curdir->line[i].line[0] =
(what == TAG_ON) ? opt_tagchar : ' ';
if (binding_state == bs_remote)
list_reline(i);
}
}
return 0;
}
int
tag_anytags(void)
{
return (tags_s.next != &tags_s);
}
syntax highlighted by Code2HTML, v. 0.9.1