#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gimp-print/gimp-print.h>
#include "gimp-print-internal.h"
#include <gimp-print/gimp-print-intl-internal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct stp_list_item
{
void *data;
struct stp_list_item *prev;
struct stp_list_item *next;
};
struct stp_list
{
int icache;
int length;
struct stp_list_item *start;
struct stp_list_item *end;
struct stp_list_item *cache;
stp_node_freefunc freefunc;
stp_node_copyfunc copyfunc;
stp_node_namefunc namefunc;
stp_node_namefunc long_namefunc;
stp_node_sortfunc sortfunc;
char *name_cache;
struct stp_list_item *name_cache_node;
char *long_name_cache;
struct stp_list_item *long_name_cache_node;
};
static void
set_name_cache(stp_list_t *list,
const char *name,
stp_list_item_t *cache)
{
if (list->name_cache)
stp_free(list->name_cache);
list->name_cache = NULL;
if (name)
list->name_cache = stp_strdup(name);
list->name_cache_node = cache;
}
static void
set_long_name_cache(stp_list_t *list,
const char *long_name,
stp_list_item_t *cache)
{
if (list->long_name_cache)
stp_free(list->long_name_cache);
list->long_name_cache = NULL;
if (long_name)
list->long_name_cache = stp_strdup(long_name);
list->long_name_cache_node = cache;
}
static inline void
clear_cache(stp_list_t *list)
{
set_name_cache(list, NULL, NULL);
set_long_name_cache(list, NULL, NULL);
}
void
stp_list_node_free_data (void *item)
{
stp_free(item);
stp_deprintf(STP_DBG_LIST, "stp_list_node_free_data destructor\n");
}
static void
null_list(void)
{
stp_erprintf("Null stp_list_t! Please report this bug.\n");
stp_abort();
}
static inline void
check_list(const stp_list_t *list)
{
if (list == NULL)
null_list();
}
static inline stp_list_item_t *
get_start_internal(const stp_list_t *list)
{
check_list(list);
return list->start;
}
static inline stp_list_item_t *
get_end_internal(const stp_list_t *list)
{
check_list(list);
return list->end;
}
stp_list_t *
stp_list_create(void)
{
stp_list_t *list =
stp_malloc(sizeof(stp_list_t));
list->icache = 0;
list->length = 0;
list->start = NULL;
list->end = NULL;
list->cache = NULL;
list->freefunc = NULL;
list->namefunc = NULL;
list->long_namefunc = NULL;
list->sortfunc = NULL;
list->copyfunc = NULL;
list->name_cache = NULL;
list->name_cache_node = NULL;
list->long_name_cache = NULL;
list->long_name_cache_node = NULL;
stp_deprintf(STP_DBG_LIST, "stp_list_head constructor\n");
return list;
}
stp_list_t *
stp_list_copy(const stp_list_t *list)
{
stp_list_t *ret;
stp_node_copyfunc copyfunc = stp_list_get_copyfunc(list);
stp_list_item_t *item = get_start_internal(list);
check_list(list);
ret = stp_list_create();
stp_list_set_copyfunc(ret, stp_list_get_copyfunc(list));
if (stp_list_get_copyfunc(list))
stp_list_set_freefunc(ret, stp_list_get_freefunc(list));
stp_list_set_namefunc(ret, stp_list_get_namefunc(list));
stp_list_set_long_namefunc(ret, stp_list_get_long_namefunc(list));
stp_list_set_sortfunc(ret, stp_list_get_sortfunc(list));
while (item)
{
void *data = item->data;
if (copyfunc)
stp_list_item_create (ret, NULL, (*copyfunc)(data));
else
stp_list_item_create(ret, NULL, data);
item = stp_list_item_next(item);
}
return ret;
}
int
stp_list_destroy(stp_list_t *list)
{
stp_list_item_t *cur;
stp_list_item_t *next;
check_list(list);
clear_cache(list);
cur = get_start_internal(list);
while(cur)
{
next = cur->next;
stp_list_item_destroy(list, cur);
cur = next;
}
stp_deprintf(STP_DBG_LIST, "stp_list_head destructor\n");
stp_free(list);
return 0;
}
int
stp_list_get_length(const stp_list_t *list)
{
check_list(list);
return list->length;
}
stp_list_item_t *
stp_list_get_start(const stp_list_t *list)
{
return get_start_internal(list);
}
stp_list_item_t *
stp_list_get_end(const stp_list_t *list)
{
return get_end_internal(list);
}
stp_list_item_t *
stp_list_get_item_by_index(const stp_list_t *list, int idx)
{
stp_list_item_t *node = NULL;
int i;
int d = 0;
int c = 0;
check_list(list);
if (idx >= list->length)
return NULL;
if (list->icache)
{
if (idx < (list->length/2))
{
if (idx > abs(idx - list->icache))
c = 1;
else
d = 0;
}
else
{
if (list->length - 1 - idx >
abs (list->length - 1 - idx - list->icache))
c = 1;
else
d = 1;
}
}
if (c)
{
if (idx > list->icache)
d = 0;
else
d = 1;
i = list->icache;
node = list->cache;
}
else
{
if (d)
{
i = list->length - 1;
node = get_end_internal(list);
}
else
{
i = 0;
node = get_start_internal(list);
}
}
while (node && i != idx)
{
if (d)
{
i--;
node = node->prev;
}
else
{
i++;
node = node->next;
}
}
((stp_list_t *)list)->icache = i;
((stp_list_t *)list)->cache = node;
return node;
}
static stp_list_item_t *
stp_list_get_item_by_name_internal(const stp_list_t *list, const char *name)
{
stp_list_item_t *node = get_start_internal(list);
while (node && strcmp(name, list->namefunc(node->data)))
{
node = node->next;
}
return node;
}
stp_list_item_t *
stp_list_get_item_by_name(const stp_list_t *list, const char *name)
{
stp_list_item_t *node = NULL;
check_list(list);
if (!list->namefunc)
return NULL;
if (list->name_cache && name && list->name_cache_node)
{
const char *new_name;
node = list->name_cache_node;
if (strcmp(name, list->name_cache) == 0 &&
strcmp(name, list->namefunc(node->data)) == 0)
return node;
node = node->next;
if (node)
{
new_name = list->namefunc(node->data);
if (strcmp(name, new_name) == 0)
{
set_name_cache((stp_list_t *) list, new_name, node);
return node;
}
}
node = list->cache;
if (node)
{
new_name = list->namefunc(node->data);
if (strcmp(name, new_name) == 0)
{
set_name_cache((stp_list_t *) list, new_name, node);
return node;
}
}
}
node = stp_list_get_item_by_name_internal(list, name);
if (node)
set_name_cache((stp_list_t *) list, name, node);
return node;
}
static stp_list_item_t *
stp_list_get_item_by_long_name_internal(const stp_list_t *list,
const char *long_name)
{
stp_list_item_t *node = get_start_internal(list);
while (node && strcmp(long_name, list->long_namefunc(node->data)))
{
node = node->next;
}
return node;
}
stp_list_item_t *
stp_list_get_item_by_long_name(const stp_list_t *list, const char *long_name)
{
stp_list_item_t *node = NULL;
check_list(list);
if (!list->long_namefunc)
return NULL;
if (list->long_name_cache && long_name && list->long_name_cache_node)
{
const char *new_long_name;
node = list->long_name_cache_node;
if (strcmp(long_name, list->long_name_cache) == 0 &&
strcmp(long_name, list->long_namefunc(node->data)) == 0)
return node;
node = node->next;
if (node)
{
new_long_name = list->long_namefunc(node->data);
if (strcmp(long_name, new_long_name) == 0)
{
set_long_name_cache((stp_list_t*) list, new_long_name, node);
return node;
}
}
node = list->cache;
if (node)
{
new_long_name = list->long_namefunc(node->data);
if (strcmp(long_name, new_long_name) == 0)
{
set_long_name_cache((stp_list_t *) list, new_long_name, node);
return node;
}
}
}
node = stp_list_get_item_by_long_name_internal(list, long_name);
if (node)
set_long_name_cache((stp_list_t *) list, long_name, node);
return node;
}
void
stp_list_set_freefunc(stp_list_t *list, stp_node_freefunc freefunc)
{
check_list(list);
list->freefunc = freefunc;
}
stp_node_freefunc
stp_list_get_freefunc(const stp_list_t *list)
{
check_list(list);
return list->freefunc;
}
void
stp_list_set_copyfunc(stp_list_t *list, stp_node_copyfunc copyfunc)
{
check_list(list);
list->copyfunc = copyfunc;
}
stp_node_copyfunc
stp_list_get_copyfunc(const stp_list_t *list)
{
check_list(list);
return list->copyfunc;
}
void
stp_list_set_namefunc(stp_list_t *list, stp_node_namefunc namefunc)
{
check_list(list);
list->namefunc = namefunc;
}
stp_node_namefunc
stp_list_get_namefunc(const stp_list_t *list)
{
check_list(list);
return list->namefunc;
}
void
stp_list_set_long_namefunc(stp_list_t *list, stp_node_namefunc long_namefunc)
{
check_list(list);
list->long_namefunc = long_namefunc;
}
stp_node_namefunc
stp_list_get_long_namefunc(const stp_list_t *list)
{
check_list(list);
return list->long_namefunc;
}
void
stp_list_set_sortfunc(stp_list_t *list, stp_node_sortfunc sortfunc)
{
check_list(list);
list->sortfunc = sortfunc;
}
stp_node_sortfunc
stp_list_get_sortfunc(const stp_list_t *list)
{
check_list(list);
return list->sortfunc;
}
int
stp_list_item_create(stp_list_t *list,
stp_list_item_t *next,
const void *data)
{
stp_list_item_t *ln;
stp_list_item_t *lnn;
check_list(list);
clear_cache(list);
ln = stp_malloc(sizeof(stp_list_item_t));
ln->prev = ln->next = NULL;
if (data)
ln->data = (void *) data;
else
{
stp_free(ln);
return 1;
}
if (list->sortfunc)
{
lnn = get_end_internal(list);
while (lnn)
{
if (list->sortfunc(lnn->data, ln->data) <= 0)
break;
lnn = lnn->prev;
}
}
#if 0
else if (stpi_get_debug_level() & STPI_DBG_LIST)
{
if (next)
{
lnn = get_start_internal(list);
while (lnn)
{
if (lnn == next)
break;
lnn = lnn->prev;
}
}
else
lnn = NULL;
}
#endif
else
lnn = next;
ln->next = lnn;
if (!ln->prev)
{
if (list->start)
ln->prev = list->end;
else
list->start = ln;
list->end = ln;
}
if (!ln->prev && ln->next)
ln->prev = ln->next->prev;
if (list->start == ln->next)
{
list->start = ln;
}
if (ln->next)
ln->next->prev = ln;
if (ln->prev)
ln->prev->next = ln;
list->length++;
stp_deprintf(STP_DBG_LIST, "stp_list_node constructor\n");
return 0;
}
int
stp_list_item_destroy(stp_list_t *list, stp_list_item_t *item)
{
check_list(list);
clear_cache(list);
list->length--;
if (list->freefunc)
list->freefunc((void *) item->data);
if (item->prev)
item->prev->next = item->next;
else
list->start = item->next;
if (item->next)
item->next->prev = item->prev;
else
list->end = item->prev;
stp_free(item);
stp_deprintf(STP_DBG_LIST, "stp_list_node destructor\n");
return 0;
}
stp_list_item_t *
stp_list_item_prev(const stp_list_item_t *item)
{
return item->prev;
}
stp_list_item_t *
stp_list_item_next(const stp_list_item_t *item)
{
return item->next;
}
void *
stp_list_item_get_data(const stp_list_item_t *item)
{
return item->data;
}
int
stp_list_item_set_data(stp_list_item_t *item, void *data)
{
if (data)
{
item->data = data;
return 0;
}
return 1;
}